Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
11 changes: 10 additions & 1 deletion src/Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -205,6 +205,7 @@ BLSCT_H = \
blsct/tokens/predicate_parser.h \
blsct/tokens/rpc.h \
blsct/wallet/address.h \
blsct/wallet/balance_proof.h \
blsct/wallet/hdchain.h \
blsct/wallet/helpers.h \
blsct/wallet/import_wallet_type.h \
Expand All @@ -214,6 +215,7 @@ BLSCT_H = \
blsct/wallet/txfactory.h \
blsct/wallet/txfactory_base.h \
blsct/wallet/txfactory_global.h \
blsct/wallet/unsigned_transaction.h \
blsct/wallet/verification.h

BLSCT_CPP = \
Expand Down Expand Up @@ -268,6 +270,7 @@ BLSCT_CPP = \
blsct/wallet/txfactory.cpp \
blsct/wallet/txfactory_base.cpp \
blsct/wallet/txfactory_global.cpp \
blsct/wallet/unsigned_transaction.cpp \
blsct/wallet/verification.cpp

.PHONY: FORCE check-symbols check-security
Expand Down Expand Up @@ -576,12 +579,13 @@ libbitcoin_node_a_SOURCES = \
blsct/range_proof/generators.cpp \
blsct/range_proof/msg_amt_cipher.cpp \
blsct/range_proof/proof_base.cpp \
blsct/range_proof/rpc.cpp \
blsct/set_mem_proof/set_mem_proof.cpp \
blsct/set_mem_proof/set_mem_proof_setup.cpp \
blsct/set_mem_proof/set_mem_proof_prover.cpp \
blsct/tokens/info.cpp \
blsct/tokens/rpc.cpp \
blsct/wallet/rpc.cpp \
blsct/wallet/unsigned_transaction.cpp \
blsct/wallet/verification.cpp \
blsct/signature.cpp \
chain.cpp \
Expand Down Expand Up @@ -736,9 +740,11 @@ libbitcoin_wallet_a_SOURCES = \
blsct/set_mem_proof/set_mem_proof_setup.cpp \
blsct/signature.cpp \
blsct/wallet/address.cpp \
blsct/wallet/balance_proof.cpp \
blsct/wallet/helpers.cpp \
blsct/wallet/keyman.cpp \
blsct/wallet/keyring.cpp \
blsct/wallet/unsigned_transaction.cpp \
blsct/wallet/rpc.cpp \
blsct/wallet/txfactory.cpp \
blsct/wallet/txfactory_base.cpp \
Expand Down Expand Up @@ -907,6 +913,7 @@ libbitcoin_consensus_a_SOURCES = \
blsct/set_mem_proof/set_mem_proof_prover.cpp \
blsct/pos/helpers.cpp \
blsct/pos/proof.cpp \
blsct/public_key.cpp \
blsct/signature.cpp \
consensus/amount.h \
consensus/merkle.cpp \
Expand Down Expand Up @@ -987,6 +994,7 @@ libbitcoin_common_a_SOURCES = \
blsct/tokens/predicate_parser.cpp \
blsct/wallet/address.cpp \
blsct/wallet/txfactory_global.cpp \
blsct/wallet/unsigned_transaction.cpp \
chainparams.cpp \
coins.cpp \
common/args.cpp \
Expand Down Expand Up @@ -1317,6 +1325,7 @@ libnaviokernel_la_SOURCES = \
blsct/tokens/predicate_exec.cpp \
blsct/tokens/predicate_parser.cpp \
blsct/wallet/txfactory_global.cpp \
blsct/wallet/unsigned_transaction.cpp \
blsct/wallet/verification.cpp \
chain.cpp \
clientversion.cpp \
Expand Down
1 change: 1 addition & 0 deletions src/Makefile.test.include
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,7 @@ BITCOIN_TESTS =\
test/blsct/set_mem_proof/set_mem_proof_tests.cpp \
test/blsct/signature_tests.cpp \
test/blsct/sign_verify_tests.cpp \
test/blsct_signature_checker_tests.cpp \
test/bswap_tests.cpp \
test/checkqueue_tests.cpp \
test/coins_tests.cpp \
Expand Down
2 changes: 2 additions & 0 deletions src/Makefile.test_util.include
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ TEST_UTIL_H = \
blsct/public_key.h \
blsct/public_keys.h \
blsct/signature.h \
blsct/wallet/unsigned_transaction.h \
blsct/wallet/txfactory_global.h \
test/util/blockfilter.h \
test/util/chainstate.h \
Expand Down Expand Up @@ -54,6 +55,7 @@ libtest_util_a_SOURCES = \
blsct/public_key.cpp \
blsct/public_keys.cpp \
blsct/signature.cpp \
blsct/wallet/unsigned_transaction.cpp \
blsct/wallet/rpc.cpp \
blsct/wallet/txfactory_global.cpp \
test/util/blockfilter.cpp \
Expand Down
2 changes: 1 addition & 1 deletion src/bench/bech32_mod.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ static void Bech32ModEncode(benchmark::Bench& bench)

static void Bech32ModDecode(benchmark::Bench& bench)
{
std::string addr = "nv1d3fqq4j2w384smpjxgm95anexe4rjwzr2pc553t0xduxuc3sd35nvatcxpnn2mjyde45sqrtfapnws3kwfc85sm3v9ekzc2r2ajnquzf09282e62xddykn25x3";
std::string addr = "nav1d3fqq4j2w384smpjxgm95anexe4rjwzr2pc553t0xduxuc3sd35nvatcxpnn2mjyde45sqrtfapnws3kwfc85sm3v9ekzc2r2ajnquzf09282e62xddykn25x3";
bench.batch(addr.size()).unit("byte").run([&] {
bech32_mod::Decode(addr);
});
Expand Down
5 changes: 4 additions & 1 deletion src/blockencodings.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,10 @@ CBlockHeaderAndShortTxIDs::CBlockHeaderAndShortTxIDs(const CBlock& block) :

void CBlockHeaderAndShortTxIDs::FillShortTxIDSelector() const {
DataStream stream{};
stream << header << posProof << nonce;
stream << header;
if (header.IsProofOfStake())
stream << posProof;
stream << nonce;
CSHA256 hasher;
hasher.Write((unsigned char*)&(*stream.begin()), stream.end() - stream.begin());
uint256 shorttxidhash;
Expand Down
10 changes: 5 additions & 5 deletions src/blsct/key_io.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,13 +19,13 @@ namespace blsct {
// - 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;
constexpr size_t DOUBLE_PUBKEY_ENC_SIZE = 3 + 1 + bech32_mod::DOUBLE_PUBKEY_DATA_ENC_SIZE + 8;

namespace bech32_hrp {
const std::string Main = "nv";
const std::string TestNet = "tn";
const std::string SigNet = "tn";
const std::string RegTest = "nr";
const std::string Main = "nav";
const std::string TestNet = "tnv";
const std::string SigNet = "snv";
const std::string RegTest = "rnav";
}

/** Encode DoublePublicKey to Bech32 or Bech32m string. Encoding must be one of BECH32 or BECH32M. */
Expand Down
80 changes: 80 additions & 0 deletions src/blsct/range_proof/rpc.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
// Copyright (c) 2024 The Navio Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#include <blsct/wallet/balance_proof.h>
#include <blsct/wallet/rpc.h>
#include <blsct/wallet/unsigned_transaction.h>
#include <coins.h>
#include <core_io.h>
#include <primitives/transaction.h>
#include <rpc/server.h>
#include <rpc/server_util.h>
#include <rpc/util.h>
#include <univalue.h>
#include <validation.h>

RPCHelpMan verifyblsctbalanceproof()
{
return RPCHelpMan{
"verifyblsctbalanceproof",
"Verifies a zero-knowledge balance proof\n",
{
{"proof", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "The serialized balance proof"},
{"additional_commitment", RPCArg::Type::STR, RPCArg::Optional::OMITTED, "The additional commitment to use for the proof signature verification"},
},
RPCResult{
RPCResult::Type::OBJ, "", "", {
{RPCResult::Type::BOOL, "valid", "Whether the proof is valid"},
{RPCResult::Type::NUM, "min_amount", "The minimum amount proven"},
}},
RPCExamples{HelpExampleCli("verifyblsctbalanceproof", "\"<hex>\"") + HelpExampleRpc("verifyblsctbalanceproof", "\"<hex>\"")},
[&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue {
LOCK(cs_main);
ChainstateManager& chainman = EnsureAnyChainman(request.context);
Chainstate& active_chainstate = chainman.ActiveChainstate();

CCoinsViewCache* coins_view;
coins_view = &active_chainstate.CoinsTip();

// Deserialize the proof
std::vector<unsigned char> proof_data = ParseHex(request.params[0].get_str());
uint256 hash = MessageHash("BLSCT_BALANCE_PROOF_" + (!request.params[1].isNull() ? request.params[1].get_str() : ""));
blsct::Message additional_commitment(hash.begin(), hash.end());
DataStream ss{proof_data};
blsct::BalanceProof proof;
try {
ss >> proof;
} catch (const std::exception) {
throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid proof format");
}

// Verify the proof
bool valid = proof.Verify(coins_view, additional_commitment);

UniValue result(UniValue::VOBJ);
result.pushKV("valid", valid);
result.pushKV("min_amount", ValueFromAmount(proof.GetMinAmount()));

return result;
},
};
}

void RegisterRangeProofRPCCommands(CRPCTable& t)
{
static const CRPCCommand commands[]{
{"blsct", &verifyblsctbalanceproof},
};
for (const auto& c : commands) {
t.appendCommand(c.name, &c);
}
}

Span<const CRPCCommand> GetRangeProofRPCCommands()
{
static const CRPCCommand commands[]{
{"blsct", &verifyblsctbalanceproof},
};
return commands;
}
3 changes: 3 additions & 0 deletions src/blsct/signature.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,9 @@ class Signature
{
public:
Signature();
Signature(const std::vector<uint8_t>& vch) {
SetVch(vch);
};

static Signature Aggregate(const std::vector<blsct::Signature>& sigs);

Expand Down
2 changes: 1 addition & 1 deletion src/blsct/tokens/rpc.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ std::vector<RPCResult> tokenInfoResult = {
RPCResult{RPCResult::Type::OBJ_DYN, "metadata", "the token metadata", {{RPCResult::Type::STR, "xxxx", "value"}}},
RPCResult{RPCResult::Type::NUM, "maxSupply", "the token max supply"},
RPCResult{RPCResult::Type::NUM, "currentSupply", true, "the token current supply"},
RPCResult{RPCResult::Type::OBJ_DYN, "mintedNft", "the nfts already minted", {{RPCResult::Type::OBJ_DYN, "index", "metadata", {{RPCResult::Type::STR, "xxxx", "value"}}}}},
RPCResult{RPCResult::Type::OBJ_DYN, "mintedNft", true, "the nfts already minted", {{RPCResult::Type::OBJ_DYN, "index", "metadata", {{RPCResult::Type::STR, "xxxx", "value"}}}}},

};

Expand Down
6 changes: 6 additions & 0 deletions src/blsct/wallet/balance_proof.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
#include <blsct/wallet/balance_proof.h>
#include <coins.h>

namespace blsct {
// Implementation is in the header file since it's all inline
} // namespace blsct
123 changes: 123 additions & 0 deletions src/blsct/wallet/balance_proof.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
// src/blsct/wallet/balance_proof.h
#ifndef BITCOIN_BLSCT_WALLET_BALANCE_PROOF_H
#define BITCOIN_BLSCT_WALLET_BALANCE_PROOF_H

#include <blsct/range_proof/bulletproofs_plus/range_proof.h>
#include <blsct/range_proof/bulletproofs_plus/range_proof_logic.h>
#include <coins.h>
#include <primitives/transaction.h>
#include <serialize.h>
#include <wallet/wallet.h>

namespace blsct {

class BalanceProof
{
private:
std::vector<COutPoint> m_outpoints;
CAmount m_min_amount;
bulletproofs_plus::RangeProof<Mcl> m_proof;
blsct::Signature m_signature;
uint16_t m_index;

public:
BalanceProof() = default;
BalanceProof(const std::vector<COutPoint>& outpoints, CAmount min_amount, const bulletproofs_plus::RangeProof<Mcl>& proof, const blsct::Signature& signature)
: m_outpoints(outpoints), m_min_amount(min_amount), m_proof(proof), m_signature(signature), m_index(0) {}

BalanceProof(const std::vector<COutPoint>& outpoints, CAmount min_amount, const wallet::CWallet& wallet, const blsct::Message& additional_commitment)
{
m_outpoints = outpoints;
m_min_amount = min_amount;

// Sum up all commitments from the outputs
MclScalar value = 0;
MclScalar gamma = 0;

if (outpoints.empty()) {
throw std::runtime_error("No outpoints provided");
}

const auto& blsct_km = const_cast<wallet::CWallet&>(wallet).GetOrCreateBLSCTKeyMan();
blsct::PrivateKey private_key;
bool has_private_key = false;
uint16_t index = 0;

for (const auto& outpoint : outpoints) {
const wallet::CWalletTx* wtx = wallet.GetWalletTx(outpoint.hash);
if (!wtx) {
throw std::runtime_error("Outpoint not found in wallet");
}

if (outpoint.n >= wtx->tx->vout.size()) {
throw std::runtime_error("Invalid output index");
}
const CTxOut& txout = wtx->tx->vout[outpoint.n];
if (!has_private_key) {
has_private_key = blsct_km->GetSpendingKeyForOutput(txout, private_key);
m_index = index;
}
if (!txout.HasBLSCTRangeProof()) {
throw std::runtime_error("Outpoint does not have BLSCT range proof");
}
auto recoveryData = wtx->GetBLSCTRecoveryData(outpoint.n);
value = value + MclScalar(recoveryData.amount);
gamma = gamma + MclScalar(recoveryData.gamma);
index++;
}

// Create range proof
bulletproofs_plus::RangeProofLogic<Mcl> prover;
range_proof::GammaSeed<Mcl> nonce(Elements<MclScalar>{1, gamma});
std::vector<uint8_t> message;
m_proof = prover.Prove({1, value}, nonce, message, TokenId(), MclScalar(min_amount));
m_signature = private_key.Sign(additional_commitment);
}

const std::vector<COutPoint>& GetOutpoints() const { return m_outpoints; }
CAmount GetMinAmount() const { return m_min_amount; }
const bulletproofs_plus::RangeProof<Mcl>& GetProof() const { return m_proof; }

bool Verify(const CCoinsViewCache& view, const blsct::Message& additional_commitment) const
{
// Sum up all commitments from the outputs
MclG1Point sum_commitment;
MclG1Point public_key;
uint16_t index = 0;
for (const auto& outpoint : m_outpoints) {
Coin coin;
if (!view.GetCoin(outpoint, coin)) {
return false;
}
if (!coin.out.HasBLSCTRangeProof()) {
return false;
}
if (index == m_index) {
public_key = coin.out.blsctData.spendingKey;
}
sum_commitment = sum_commitment + coin.out.blsctData.rangeProof.Vs[0];
index++;
}

const_cast<bulletproofs_plus::RangeProof<Mcl>&>(m_proof).Vs.Clear();
const_cast<bulletproofs_plus::RangeProof<Mcl>&>(m_proof).Vs.Add(sum_commitment);

// Create a range proof with seed for verification
bulletproofs_plus::RangeProofWithSeed<Mcl> proof(m_proof, TokenId(), MclScalar(m_min_amount));
std::vector<bulletproofs_plus::RangeProofWithSeed<Mcl>> proofs;
proofs.push_back(proof);

// Verify the range proof
bulletproofs_plus::RangeProofLogic<Mcl> prover;
return prover.Verify(proofs) && blsct::PublicKey(public_key).Verify(additional_commitment, m_signature);
}

SERIALIZE_METHODS(BalanceProof, obj)
{
READWRITE(obj.m_outpoints, obj.m_min_amount, obj.m_proof, obj.m_signature, obj.m_index);
}
};

} // namespace blsct

#endif // BITCOIN_BLSCT_WALLET_BALANCE_PROOF_H
Loading
Loading