From 08523e4d6752ab80a85514086c8f1d07e2e99c83 Mon Sep 17 00:00:00 2001 From: gogoex <110195520+gogoex@users.noreply.github.com> Date: Sat, 13 Jul 2024 17:18:30 +0900 Subject: [PATCH 01/44] add ext api working up to range proof prove --- .gitignore | 1 + src/Makefile.am | 6 + src/blsct/arith/mcl/mcl.h | 2 + src/blsct/external_api/blsct.cpp | 1146 +++++++++++++++++++++++++++++- src/blsct/external_api/blsct.h | 578 ++++++++++++++- src/blsct/key_io.cpp | 62 ++ src/blsct/key_io.h | 47 ++ src/blsct/pos/proof.cpp | 2 +- src/blsct/public_key.cpp | 5 + src/blsct/public_key.h | 1 + src/key_io.cpp | 52 +- src/key_io.h | 1 + 12 files changed, 1851 insertions(+), 52 deletions(-) create mode 100644 src/blsct/key_io.cpp create mode 100644 src/blsct/key_io.h diff --git a/.gitignore b/.gitignore index 1bcd56736aed2..af9afa9f269e8 100644 --- a/.gitignore +++ b/.gitignore @@ -147,3 +147,4 @@ compile_commands.json # others null.d +libnavioconsensus.pc diff --git a/src/Makefile.am b/src/Makefile.am index 907a83aea8c92..537e37d6c8f67 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -211,6 +211,7 @@ BLSCT_CPP = \ blsct/arith/elements.cpp \ blsct/arith/mcl/mcl_g1point.cpp \ blsct/arith/mcl/mcl_scalar.cpp \ + blsct/bech32_mod.cpp \ blsct/building_block/g_h_gi_hi_zero_verifier.cpp \ blsct/building_block/generator_deriver.cpp \ blsct/building_block/imp_inner_prod_arg.cpp \ @@ -221,6 +222,7 @@ BLSCT_CPP = \ blsct/double_public_key.cpp \ blsct/eip_2333/bls12_381_keygen.cpp \ blsct/external_api/blsct.cpp \ + blsct/key_io.cpp \ blsct/pos/helpers.cpp \ blsct/pos/pos.cpp \ blsct/pos/proof_logic.cpp \ @@ -1430,6 +1432,10 @@ libblsct_a_SOURCES = \ crypto/sha256_x86_shani.cpp \ crypto/sha256.cpp \ blsct/external_api/blsct.cpp \ + support/cleanse.cpp \ + support/lockedpool.cpp \ + uint256.cpp \ + util/strencodings.cpp \ $(BLSCT_CPP) libblsct_a_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) libblsct_a_CPPFLAGS = $(AM_CPPFLAGS) $(BLS_INCLUDES) $(BOOST_CPPFLAGS) diff --git a/src/blsct/arith/mcl/mcl.h b/src/blsct/arith/mcl/mcl.h index 00ba3d7e92c39..68769af1cf48e 100644 --- a/src/blsct/arith/mcl/mcl.h +++ b/src/blsct/arith/mcl/mcl.h @@ -10,6 +10,7 @@ #define NAVIO_BLSCT_ARITH_MCL_MCL_H #include +#include #include #include @@ -21,6 +22,7 @@ struct Mcl { using Scalar = MclScalar; using Point = MclG1Point; using Util = MclUtil; + using Init = MclInit; }; #endif // NAVIO_BLSCT_ARITH_MCL_MCL_H diff --git a/src/blsct/external_api/blsct.cpp b/src/blsct/external_api/blsct.cpp index f0bef0eb7c8e7..89e9413465ca4 100644 --- a/src/blsct/external_api/blsct.cpp +++ b/src/blsct/external_api/blsct.cpp @@ -1,24 +1,1150 @@ +#include +#include +#include +#include #include -#include -#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include #include +#include +#include +#include +#include +#include + +static std::string g_chain; +static std::mutex g_init_mutex; +static std::mutex g_set_chain_mutex; +static bulletproofs::RangeProofLogic* g_rpl; +static bool g_is_little_endian; extern "C" { -void BlsctInit() { - MclInit for_side_effect_only; +static bool is_little_endian() { + uint16_t n = 1; + uint8_t* p = (uint8_t*) &n; + return *p == 1; +} + +void init() +{ + std::lock_guard lock(g_init_mutex); + + Mcl::Init for_side_effect_only; + + g_chain = blsct::bech32_hrp::Main; + g_is_little_endian = is_little_endian(); + g_rpl = new bulletproofs::RangeProofLogic(); +} + +bool set_chain(enum Chain chain) +{ + std::lock_guard lock(g_set_chain_mutex); + if (!g_chain.empty()) { + return false; + } + + switch (chain) { + case MainNet: + g_chain = blsct::bech32_hrp::Main; + break; + + case TestNet: + g_chain = blsct::bech32_hrp::TestNet; + break; + + case SigNet: + g_chain = blsct::bech32_hrp::SigNet; + break; + + case RegTest: + g_chain = blsct::bech32_hrp::RegTest; + break; + } + return true; +} + +BlsctPoint* gen_random_point() { + NEW(BlsctPoint, blsct_point); + auto x = Point::Rand(); + SERIALIZE_AND_COPY(x, blsct_point); + return blsct_point; +} + +BlsctScalar* gen_random_scalar() { + NEW(BlsctScalar, blsct_scalar); + auto x = Scalar::Rand(true); + SERIALIZE_AND_COPY(x, blsct_scalar); + return blsct_scalar; +} + +BlsctScalar* gen_scalar( + const uint64_t n +) { + Scalar scalar_n(n); + NEW(BlsctScalar, blsct_scalar); + SERIALIZE_AND_COPY(scalar_n, blsct_scalar); + return blsct_scalar; +} + +void dispose_point(BlsctPoint* blsct_point) +{ + if (blsct_point != nullptr) delete[] blsct_point; +} + +void dispose_scalar(BlsctScalar* blsct_scalar) +{ + if (blsct_scalar != nullptr) delete[] blsct_scalar; +} + +void dispose_public_key(BlsctPubKey* blsct_pub_key) +{ + if (blsct_pub_key != nullptr) delete[] blsct_pub_key; +} + +uint64_t scalar_to_uint64(BlsctScalar* blsct_scalar) +{ + Scalar scalar; + UNSERIALIZE_FROM_BYTE_ARRAY_WITH_STREAM(blsct_scalar, SCALAR_SIZE, scalar); + return scalar.GetUint64(); +} + +BlsctPubKey* gen_random_public_key() { + auto vec = Point::Rand().GetVch(); + blsct::PublicKey pub_key(vec); + + NEW(BlsctPubKey, blsct_pub_key); + SERIALIZE_AND_COPY(pub_key, blsct_pub_key); + + return blsct_pub_key; +} + +BlsctRetVal* decode_address( + const char* blsct_enc_addr +) { + try { + if (strlen(blsct_enc_addr) != ENCODED_DPK_STR_SIZE) { + return new BlsctRetVal { + RetValType::DecAddr, + BLSCT_BAD_DPK_SIZE, + }; + } + std::string enc_addr(blsct_enc_addr); + auto maybe_dpk = blsct::DecodeDoublePublicKey(g_chain, enc_addr); + if (maybe_dpk) { + auto dpk = maybe_dpk.value(); + if (dpk.IsValid()) { + auto buf = dpk.GetVch(); + uint8_t* dec_addr = new uint8_t[DOUBLE_PUBLIC_KEY_SIZE]; + std::memcpy(dec_addr, &buf[0], DOUBLE_PUBLIC_KEY_SIZE); + + return new BlsctRetVal { + RetValType::DecAddr, + BLSCT_SUCCESS, + dec_addr, + }; + } + } + } catch(...) {} + + return new BlsctRetVal { + RetValType::DecAddr, + BLSCT_EXCEPTION, + }; +} + +BlsctStrRetVal* encode_address( + const void* void_blsct_dpk, + const enum AddressEncoding encoding +) { + try { + UNVOID(BlsctDoublePubKey, blsct_dpk); + + if (encoding != Bech32 && encoding != Bech32M) { + return new BlsctStrRetVal { + BLSCT_UNKNOWN_ENCODING, + }; + } + auto bech32_encoding = encoding == Bech32 ? + bech32_mod::Encoding::BECH32 : bech32_mod::Encoding::BECH32M; + + auto blsct_dpk_u8 = U8C(blsct_dpk, BlsctDoublePubKey); + std::vector dpk_vec(blsct_dpk_u8, blsct_dpk_u8 + blsct::DoublePublicKey::SIZE); + auto dpk = blsct::DoublePublicKey(dpk_vec); + + auto enc_addr = new char[ENCODED_DPK_STR_BUF_SIZE]; + auto enc_dpk_str = EncodeDoublePublicKey(g_chain, bech32_encoding, dpk); + std::memcpy(enc_addr, enc_dpk_str.c_str(), ENCODED_DPK_STR_BUF_SIZE); + enc_addr[ENCODED_DPK_STR_BUF_SIZE - 1] = 0; // null-terminate c-str + + return new BlsctStrRetVal { + BLSCT_SUCCESS, + enc_addr, + }; + } catch(...) {} + + return new BlsctStrRetVal { + BLSCT_EXCEPTION, + }; +} + +BlsctRetVal* gen_double_pub_key( + const BlsctPubKey* blsct_pk1, + const BlsctPubKey* blsct_pk2 +) { + auto blsct_pk1_u8 = U8C(blsct_pk1, BlsctPubKey); + auto blsct_pk2_u8 = U8C(blsct_pk2, BlsctPubKey); + + blsct::PublicKey pk1, pk2; + std::vector blsct_pk1_vec { + blsct_pk1_u8, + blsct_pk1_u8 + blsct::PublicKey::SIZE + }; + std::vector blsct_pk2_vec { + blsct_pk2_u8, + blsct_pk2_u8 + blsct::PublicKey::SIZE + }; + pk1.SetVch(blsct_pk1_vec); + pk2.SetVch(blsct_pk2_vec); + + NEW(BlsctDoublePubKey, blsct_dpk); + blsct::DoublePublicKey dpk(pk1, pk2); + SERIALIZE_AND_COPY(dpk, blsct_dpk); + + return new BlsctRetVal { + RetValType::DoublePubKey, + BLSCT_SUCCESS, + blsct_dpk, + }; +} + +void dispose_double_pub_key(const BlsctDoublePubKey* blsct_dpk) +{ + if (blsct_dpk != nullptr) delete[] blsct_dpk; +} + +BlsctRetVal* gen_token_id_with_subid( + const uint64_t token, + const uint64_t subid +) { + uint256 token_uint256; + auto data = token_uint256.data(); + uint64_t n = token; + for (size_t i=0; i<8; i++) { + data[i] = n & 0xFF; + n >>= 8; // Shift the value right by 8 bits to process the next byte + } + TokenId token_id(token_uint256, subid); + NEW(BlsctTokenId, blsct_token_id); + SERIALIZE_AND_COPY_WITH_STREAM(token_id, blsct_token_id); + + return new BlsctRetVal { + RetValType::TokenIdent, + BLSCT_SUCCESS, + blsct_token_id, + }; +} + +BlsctRetVal* gen_token_id( + const uint64_t token +) { + return gen_token_id_with_subid( + token, + UINT64_MAX + ); +} + +BlsctRetVal* gen_default_token_id() { + TokenId token_id; + NEW(BlsctTokenId, blsct_token_id); + SERIALIZE_AND_COPY_WITH_STREAM(token_id, blsct_token_id); + + return new BlsctRetVal { + RetValType::TokenIdent, + BLSCT_SUCCESS, + blsct_token_id, + }; +} + +BlsctRpRetVal* build_range_proof( + const void* vp_uint64_vs, + const size_t num_uint64_vs, + const BlsctPoint* blsct_nonce, + const char* blsct_message, + const size_t blsct_message_size, + const BlsctTokenId* blsct_token_id +) { + try { + auto uint64_vs = static_cast*>(vp_uint64_vs); + // uint64_t to Scalar + Scalars vs; + for (uint64_t uint64_v : *uint64_vs) { + if (uint64_v > INT64_MAX) { + return new BlsctRpRetVal { + BLSCT_VALUE_OUTSIDE_THE_RANGE, + }; + } + Mcl::Scalar x(static_cast(uint64_v)); + vs.Add(x); + } + + // blsct_nonce to nonce + Mcl::Point nonce; + auto blsct_nonce_u8 = U8C(blsct_nonce, BlsctPoint); + std::vector ser_point( + blsct_nonce_u8, blsct_nonce_u8 + POINT_SIZE + ); + nonce.SetVch(ser_point); + + // blsct_message to message + std::vector message( + blsct_message, blsct_message + blsct_message_size + 1 // +1 for null term + ); + + // blsct_token_id to token_id + TokenId token_id; + { + DataStream st{}; + std::vector token_id_vec( + *blsct_token_id, *blsct_token_id + TOKEN_ID_SIZE + ); + st << token_id_vec; + token_id.Unserialize(st); + } + + // range_proof to blsct_range_proof + auto range_proof = g_rpl->Prove( + vs, + nonce, + message, + token_id + ); + NEW(BlsctRangeProof, blsct_range_proof); + { + DataStream st{}; + range_proof.Serialize(st); + std::memcpy(blsct_range_proof, st.data(), st.size()); + } + return new BlsctRpRetVal { + BLSCT_SUCCESS, + blsct_range_proof, + }; + + } catch(...) {} + + return new BlsctRpRetVal { + BLSCT_EXCEPTION, + }; +} + +BlsctBoolRetVal* verify_range_proofs( + const void* vp_range_proofs +) { + try { + auto range_proofs = static_cast>*>(vp_range_proofs); + + std::vector> range_proof_w_seeds; + + for(auto rp: *range_proofs) { + auto rp_w_seed = bulletproofs::RangeProofWithSeed(rp); + range_proof_w_seeds.push_back(rp_w_seed); + } + bool is_valid = g_rpl->Verify(range_proof_w_seeds); + + return new BlsctBoolRetVal { + BLSCT_SUCCESS, + is_valid, + }; + } catch(...) {} + + return new BlsctBoolRetVal { + BLSCT_EXCEPTION, + }; +} + +/* +void blsct_gen_out_point( + const char* tx_id_c_str, + const uint32_t n, + BlsctOutPoint blsct_out_point +) { + // txid is 32 bytes, and represented as hex string of size 64 + std::string tx_id_str(tx_id_c_str, 64); + auto tx_id = TxidFromString(tx_id_str); + COutPoint out_point { tx_id, n }; + + SERIALIZE_AND_COPY_WITH_STREAM( + out_point, + blsct_out_point + ); +} + +static blsct::PrivateKey blsct_scalar_to_priv_key( + const BlsctScalar blsct_scalar +) { + Scalar scalar; + std::vector vec {blsct_scalar, blsct_scalar + Scalar::SERIALIZATION_SIZE}; + scalar.SetVch(vec); + + blsct::PrivateKey priv_key(scalar); + return priv_key; +} + +void blsct_gen_random_priv_key( + BlsctScalar blsct_priv_key +) { + Scalar priv_key = Scalar::Rand(); + SERIALIZE_AND_COPY(priv_key, blsct_priv_key); +} + +void blsct_gen_priv_key( + const uint8_t priv_key[PRIVATE_KEY_SIZE], + BlsctScalar blsct_priv_key +) { + std::vector vec { priv_key, priv_key + PRIVATE_KEY_SIZE }; + Scalar tmp(vec); + SERIALIZE_AND_COPY(tmp, blsct_priv_key); +} + +void blsct_uint64_to_blsct_uint256( + const uint64_t n, + BlsctUint256 blsct_uint256 +) { + std::memset(blsct_uint256, 0, UINT256_SIZE); + uint64_t tmp = n; + + // BlsctUint256 is little-endian + for (size_t i=0; i<8; ++i) { + blsct_uint256[g_is_little_endian ? i : 32 - i] = + static_cast(tmp & 0xFF); + tmp >>= 8; + } +} + +bool blsct_is_valid_point(BlsctPoint blsct_point) +{ + std::vector ser_point {blsct_point, blsct_point + POINT_SIZE}; + Point p; + p.SetVch(ser_point); + return p.IsValid(); +} + +void blsjct_hash_byte_str_to_public_key( + const char* src_str, + const size_t src_str_size, + BlsctPubKey blsct_pub_key +) { + std::vector src_vec {src_str, src_str + src_str_size}; + auto point = Point::HashAndMap(src_vec); + SERIALIZE_AND_COPY(point, blsct_pub_key); } -void BlsctTest() { +void blsct_gen_dpk_with_keys_and_sub_addr_id( + const BlsctPrivKey blsct_view_key, + const BlsctPubKey blsct_spending_key, + const int64_t account, + const uint64_t address, + BlsctDoublePubKey blsct_dpk +) { + blsct::PrivateKey view_key; + UNSERIALIZE_FROM_BYTE_ARRAY_WITH_STREAM(blsct_view_key, PRIVATE_KEY_SIZE, view_key); - Mcl::Scalar a(1); - Mcl::Scalar b(2); + blsct::PublicKey spending_key; + UNSERIALIZE_FROM_BYTE_ARRAY_WITH_STREAM(blsct_spending_key, PUBLIC_KEY_SIZE, spending_key); - auto c = a + b; + blsct::SubAddressIdentifier sub_addr_id { account, address }; + blsct::SubAddress sub_addr(view_key, spending_key, sub_addr_id); - auto s = c.GetString(); + auto dpk = std::get(sub_addr.GetDestination()); + SERIALIZE_AND_COPY(dpk, blsct_dpk); +} + +void blsct_dpk_to_sub_addr( + const BlsctDoublePubKey blsct_dpk, + BlsctSubAddr blsct_sub_addr +) { + blsct::DoublePublicKey dpk; + UNSERIALIZE_FROM_BYTE_ARRAY_WITH_STREAM(blsct_dpk, DOUBLE_PUBLIC_KEY_SIZE, dpk); + + blsct::SubAddress sub_addr(dpk); + SERIALIZE_AND_COPY_WITH_STREAM(sub_addr, blsct_sub_addr); +} - std::cout << "The answer is " << s << std::endl; +bool blsct_decode_token_id( + const BlsctTokenId blsct_token_id, + BlsctTokenIdDe* blsct_token_id_de +) { + TokenId token_id; + UNSERIALIZE_FROM_BYTE_ARRAY_WITH_STREAM( + blsct_token_id, + TOKEN_ID_SIZE, + token_id + ); + auto& token = token_id.token; + blsct_token_id_de->token = token.GetUint64(0); + + bool is_token_within_uint64_range = true; + for (auto it = token.begin() + 8; it != token.end(); ++it) { + if (*it != 0) { + is_token_within_uint64_range = false; + blsct_token_id_de->token = std::numeric_limits::max(); + } + } + blsct_token_id_de->subid = token_id.subid; + + return is_token_within_uint64_range; } +BLSCT_RESULT blsct_recover_amount( + BlsctAmountRecoveryRequest blsct_amount_recovery_reqs[], + const size_t num_reqs +) { + try { + // build AmountRecoveryRequests + std::vector> reqs; + + for(size_t i=0; i range_proof; + blsct_range_proof_to_range_proof( + r.range_proof, + range_proof + ); + + auto req = bulletproofs::AmountRecoveryRequest::of( + range_proof, + nonce + ); + reqs.push_back(req); + } + + auto recovery_results = g_rpl->RecoverAmounts(reqs); + + // initially mark all the requests as failed + for(size_t i=0; i vec( + blsct_point, + blsct_point + Point::SERIALIZATION_SIZE + ); + return point.SetVch(vec); +} + +static inline void from_blsct_scalar_to_mcl_scalar( + const BlsctScalar blsct_scalar, + Scalar& scalar +) { + std::vector vec( + blsct_scalar, + blsct_scalar + Scalar::SERIALIZATION_SIZE + ); + scalar.SetVch(vec); +} + +BLSCT_RESULT blsct_derive_sub_addr( + const BlsctPrivKey blsct_view_key, + const BlsctPubKey blsct_spend_key, + const BlsctSubAddrId blsct_sub_addr_id, + BlsctSubAddr blsct_sub_addr +) { + blsct::PrivateKey view_key; + UNSERIALIZE_AND_COPY_WITH_STREAM( + blsct_view_key, + blsct::PrivateKey::SIZE, + view_key + ); + + blsct::PublicKey spend_key; + UNSERIALIZE_AND_COPY_WITH_STREAM( + blsct_spend_key, + blsct::PublicKey::SIZE, + spend_key + ); + + blsct::SubAddressIdentifier sub_addr_id; + UNSERIALIZE_AND_COPY_WITH_STREAM( + blsct_sub_addr_id, + blsct::SubAddressIdentifier::SIZE, + sub_addr_id + ); + + auto sub_addr = blsct::DeriveSubAddress(view_key, spend_key, sub_addr_id); + SERIALIZE_AND_COPY_WITH_STREAM( + sub_addr, + blsct_sub_addr + ); + + return BLSCT_SUCCESS; +} + +BLSCT_RESULT blsct_calculate_nonce( + const BlsctPoint blsct_blinding_pub_key, + const BlsctScalar blsct_view_key, + BlsctPoint blsct_nonce +) { + TRY_DEFINE_MCL_POINT_FROM(blsct_blinding_pub_key, blinding_pub_key); + TRY_DEFINE_MCL_SCALAR_FROM(blsct_view_key, view_key); + + auto nonce = blsct::CalculateNonce(blinding_pub_key, view_key); + SERIALIZE_AND_COPY(nonce, blsct_nonce); + + return BLSCT_SUCCESS; +} + +BLSCT_RESULT blsct_from_seed_to_child_key( + const BlsctScalar blsct_seed, + BlsctScalar blsct_child_key +) { + TRY_DEFINE_MCL_SCALAR_FROM(blsct_seed, seed); + + auto child_key = blsct::FromSeedToChildKey(seed); + SERIALIZE_AND_COPY(child_key, blsct_child_key); + + return BLSCT_SUCCESS; +} + +BLSCT_RESULT blsct_from_child_key_to_tx_key( + const BlsctScalar blsct_child_key, + BlsctScalar blsct_tx_key +) { + TRY_DEFINE_MCL_SCALAR_FROM(blsct_child_key, child_key); + + auto tx_key = blsct::FromChildToTransactionKey(child_key); + SERIALIZE_AND_COPY(tx_key, blsct_tx_key); + + return BLSCT_SUCCESS; +} + +BLSCT_RESULT blsct_from_child_key_to_master_blinding_key( + const BlsctScalar blsct_child_key, + BlsctScalar blsct_master_blinding_key +) { + TRY_DEFINE_MCL_SCALAR_FROM(blsct_child_key, child_key); + + Scalar master_blinding_key = + blsct::FromChildToMasterBlindingKey(child_key); + + SERIALIZE_AND_COPY(master_blinding_key, blsct_master_blinding_key); + + return BLSCT_SUCCESS; +}; + +BLSCT_RESULT blsct_from_child_key_to_token_key( + const BlsctScalar blsct_child_key, + BlsctScalar blsct_token_key +) { + TRY_DEFINE_MCL_SCALAR_FROM(blsct_child_key, child_key); + + auto token_key = blsct::FromChildToTokenKey(child_key); + SERIALIZE_AND_COPY(token_key, blsct_token_key); + + return BLSCT_SUCCESS; +} + +BLSCT_RESULT blsct_from_tx_key_to_view_key( + const BlsctScalar blsct_tx_key, + BlsctPrivKey blsct_view_key +) { + TRY_DEFINE_MCL_SCALAR_FROM(blsct_tx_key, tx_key); + + auto scalar_view_key = + blsct::FromTransactionToViewKey(tx_key); + blsct::PrivateKey view_key(scalar_view_key); + + SERIALIZE_AND_COPY(scalar_view_key, blsct_view_key); + + return BLSCT_SUCCESS; +} + +BLSCT_RESULT blsct_from_tx_key_to_spending_key( + const BlsctScalar blsct_tx_key, + BlsctScalar blsct_spending_key +) { + TRY_DEFINE_MCL_SCALAR_FROM(blsct_tx_key, tx_key); + + auto spending_key = blsct::FromTransactionToSpendingKey(tx_key); + SERIALIZE_AND_COPY(spending_key, blsct_spending_key); + + return BLSCT_SUCCESS; +} + +BLSCT_RESULT blsct_calculate_view_tag( + const BlsctPoint blsct_blinding_pub_key, + const BlsctScalar blsct_view_key, + BlsctViewTag blsct_view_tag +) { + TRY_DEFINE_MCL_POINT_FROM(blsct_blinding_pub_key, blinding_pub_key); + TRY_DEFINE_MCL_SCALAR_FROM(blsct_view_key, view_key); + + *blsct_view_tag = blsct::CalculateViewTag(blinding_pub_key, view_key); + + return BLSCT_SUCCESS; +} + +BLSCT_RESULT blsct_calculate_hash_id( + const BlsctPoint blsct_blinding_pub_key, + const BlsctPoint blsct_spending_key, + const BlsctScalar blsct_view_key, + BlsctKeyId blsct_hash_id +) { + TRY_DEFINE_MCL_POINT_FROM(blsct_blinding_pub_key, blinding_pub_key); + TRY_DEFINE_MCL_POINT_FROM(blsct_spending_key, spending_key); + TRY_DEFINE_MCL_SCALAR_FROM(blsct_view_key, view_key); + + auto hash_id = blsct::CalculateHashId(blinding_pub_key, spending_key, view_key); + SERIALIZE_AND_COPY_WITH_STREAM(hash_id, blsct_hash_id); + + return BLSCT_SUCCESS; +} + +BLSCT_RESULT blsct_calc_priv_spending_key( + const BlsctPoint blsct_blinding_pub_key, + const BlsctPoint blsct_spending_key, + const BlsctScalar blsct_view_key, + const int64_t& account, + const uint64_t& address, + BlsctScalar blsct_priv_spending_key +) { + TRY_DEFINE_MCL_POINT_FROM(blsct_blinding_pub_key, blinding_pub_key); + TRY_DEFINE_MCL_SCALAR_FROM(blsct_view_key, view_key); + TRY_DEFINE_MCL_SCALAR_FROM(blsct_spending_key, spending_key); + + auto priv_spending_key = blsct::CalculatePrivateSpendingKey( + blinding_pub_key, + view_key, + spending_key, + account, + address + ); + SERIALIZE_AND_COPY(priv_spending_key, blsct_priv_spending_key); + + return BLSCT_SUCCESS; +} + +void blsct_build_tx_in( + const uint64_t amount, + const uint64_t gamma, + const BlsctScalar spending_key, + const BlsctTokenId token_id, + const BlsctOutPoint out_point, + const bool rbf, + BlsctTxIn* const tx_in +) { + tx_in->amount = amount; + tx_in->gamma = gamma; + tx_in->rbf = rbf; + + BLSCT_COPY(spending_key, tx_in->spending_key); + BLSCT_COPY(token_id, tx_in->token_id); + BLSCT_COPY(out_point, tx_in->out_point); +} + +BLSCT_RESULT blsct_build_tx_out( + const BlsctSubAddr blsct_dest, + const uint64_t amount, + const char* memo, + const BlsctTokenId blsct_token_id, + const TxOutputType output_type, + const uint64_t min_stake, + BlsctTxOut* const tx_out +) { + tx_out->amount = amount; + + // +1 for null terminator + size_t memo_len = std::strlen(memo); + if (memo_len + 1 > MEMO_BUF_SIZE) { + return BLSCT_MEMO_TOO_LONG; + } + // copy the memo including the null terminator + std::memcpy(tx_out->memo, memo, memo_len + 1); + + tx_out->output_type = output_type; + tx_out->min_stake = min_stake; + + BLSCT_COPY(blsct_dest, tx_out->dest); + BLSCT_COPY(blsct_token_id, tx_out->token_id); + + return BLSCT_SUCCESS; +} + +BLSCT_RESULT blsct_build_tx( + const BlsctTxIn blsct_tx_ins[], + const size_t num_blsct_tx_ins, + const BlsctTxOut blsct_tx_outs[], + const size_t num_blsct_tx_outs, + uint8_t* ser_tx, + size_t* ser_tx_size, + size_t* in_amount_err_index, + size_t* out_amount_err_index +) { + blsct::TxFactoryBase psbt; + + for (size_t i=0; i std::numeric_limits::max()) { + *in_amount_err_index = i; + return BLSCT_IN_AMOUNT_ERROR; + } + + Scalar gamma(tx_in.gamma); + + blsct::PrivateKey spending_key = + blsct_scalar_to_priv_key(tx_in.spending_key); + + TokenId token_id; + UNSERIALIZE_FROM_BYTE_ARRAY_WITH_STREAM( + tx_in.token_id, TOKEN_ID_SIZE, token_id + ); + + COutPoint out_point; + UNSERIALIZE_FROM_BYTE_ARRAY_WITH_STREAM( + tx_in.out_point, OUT_POINT_SIZE, out_point + ); + + psbt.AddInput( + tx_in.amount, + gamma, + spending_key, + token_id, + out_point + ); + } + + for (size_t i=0; i std::numeric_limits::max()) { + *out_amount_err_index = i; + return BLSCT_OUT_AMOUNT_ERROR; + } + + blsct::DoublePublicKey dest; + UNSERIALIZE_FROM_BYTE_ARRAY_WITH_STREAM( + tx_out.dest, DOUBLE_PUBLIC_KEY_SIZE, dest + ); + + std::string memo(tx_out.memo); + + TokenId token_id; + UNSERIALIZE_FROM_BYTE_ARRAY_WITH_STREAM( + tx_out.token_id, TOKEN_ID_SIZE, token_id + ); + + blsct::CreateOutputType out_type; + if (tx_out.output_type == TxOutputType::Normal) { + out_type = blsct::CreateOutputType::NORMAL; + } else if (tx_out.output_type == TxOutputType::StakedCommitment) { + out_type = blsct::CreateOutputType::STAKED_COMMITMENT; + } else { + return BLSCT_BAD_OUT_TYPE; + } + psbt.AddOutput( + dest, + tx_out.amount, + tx_out.memo, + token_id, + out_type, + tx_out.min_stake + ); + } + + blsct::DoublePublicKey change_dest; + auto maybe_tx = psbt.BuildTx(change_dest); + + if (!maybe_tx.has_value()) { + return BLSCT_FAILURE; + } + auto tx = maybe_tx.value(); + + DataStream st{}; + TransactionSerParams params { .allow_witness = true }; + ParamsStream ps {params, st}; + tx.Serialize(ps); + + // if provided buffer is not large enough to store the + // serialized tx, return error with the required buffer size + if (st.size() > *ser_tx_size) { + *ser_tx_size = st.size(); + return BLSCT_BUFFER_TOO_SMALL; + } + // return the serialized tx with the size + + // this line gets the following warning, but the warning can be safely ignored + // warning: stack protector not protecting local variables: variable length buffer [-Wstack-protector] + std::memcpy(ser_tx, st.data(), st.size()); + + *ser_tx_size = st.size(); + + return BLSCT_SUCCESS; +} + +void blsct_deserialize_tx( + const uint8_t* ser_tx, + const size_t ser_tx_size, + BlsctTransaction** const blsct_tx +) { + // deserialize CMutableTransaction + CMutableTransaction tx; + DataStream st{}; + TransactionSerParams params { .allow_witness = true }; + ParamsStream ps {params, st}; + + for (size_t i=0; iversion = tx.nVersion; + (*blsct_tx)->lock_time = tx.nLockTime; + + // tx signature + SERIALIZE_AND_COPY(tx.txSig, (*blsct_tx)->tx_sig); + + // CTxIn + (*blsct_tx)->num_ins = tx.vin.size(); + (*blsct_tx)->ins = new BlsctCTxIn[tx.vin.size()]; + + for (size_t i=0; iins[i]; + auto& tx_in = tx.vin[i]; + + in.sequence = tx_in.nSequence; + + // prev out + in.prev_out.n = tx_in.prevout.n; + std::memcpy( + in.prev_out.hash, + tx_in.prevout.hash.data(), + UINT256_SIZE + ); + + // script_sig + in.script_sig.size = tx_in.scriptSig.size(); + std::memcpy( + in.script_sig.script, + tx_in.scriptSig.data(), + tx_in.scriptSig.size() + ); + + // script witness + in.script_witness.size = tx_in.scriptWitness.stack.size(); + in.script_witness.stack = new BlsctVector[in.script_witness.size]; + + for (size_t i=0; inum_outs = tx.vout.size(); + (*blsct_tx)->outs = new BlsctCTxOut[tx.vout.size()]; + + for (size_t i=0; iouts[i]; + auto& tx_out = tx.vout[i]; + + // value + out.value = tx_out.nValue; + + // script_pubkey + out.script_pubkey.size = tx_out.scriptPubKey.size(); + std::memcpy( + out.script_pubkey.script, + tx_out.scriptPubKey.data(), + tx_out.scriptPubKey.size() + ); + + // token_id + SERIALIZE_AND_COPY_WITH_STREAM(tx_out.tokenId, out.token_id); + + // blsct_data + if (!tx_out.IsBLSCT()) { + out.blsct_data = nullptr; + continue; + } + out.blsct_data = new BlsctBlsctData(); + auto& blsct_data = *out.blsct_data; + + blsct_data.view_tag = tx_out.blsctData.viewTag; + + SERIALIZE_AND_COPY( + tx_out.blsctData.spendingKey, + blsct_data.spending_key + ); + SERIALIZE_AND_COPY( + tx_out.blsctData.ephemeralKey, + blsct_data.ephemeral_key + ); + SERIALIZE_AND_COPY( + tx_out.blsctData.blindingKey, + blsct_data.blinding_key + ); + + // range_proof + auto& tx_range_proof = tx_out.blsctData.rangeProof; + auto& range_proof = blsct_data.range_proof; + + SERIALIZE_AND_COPY(tx_range_proof.A, range_proof.A); + SERIALIZE_AND_COPY(tx_range_proof.S, range_proof.S); + SERIALIZE_AND_COPY(tx_range_proof.T1, range_proof.T1); + SERIALIZE_AND_COPY(tx_range_proof.T2, range_proof.T2); + SERIALIZE_AND_COPY(tx_range_proof.mu, range_proof.mu); + SERIALIZE_AND_COPY(tx_range_proof.tau_x, range_proof.tau_x); + SERIALIZE_AND_COPY(tx_range_proof.a, range_proof.a); + SERIALIZE_AND_COPY(tx_range_proof.b, range_proof.b); + SERIALIZE_AND_COPY(tx_range_proof.t_hat, range_proof.t_hat); + } +} + +void blsct_dispose_tx( + BlsctTransaction** const blsct_tx +) { + auto& tx = *(*blsct_tx); + + if (tx.ins) { + // dispose memory dynamically allocated to script_witness + for (size_t i=0; i +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* constants */ +#define PUBLIC_KEY_SIZE 48 +#define DOUBLE_PUBLIC_KEY_SIZE PUBLIC_KEY_SIZE * 2 +#define SUBADDRESS_SIZE DOUBLE_PUBLIC_KEY_SIZE +#define SUBADDRESS_ID_SIZE 16 +#define ENCODED_DPK_STR_SIZE 165 +#define ENCODED_DPK_STR_BUF_SIZE ENCODED_DPK_STR_SIZE + 1 /* 1 for c-str null termination */ +#define KEY_ID_SIZE 20 +#define POINT_SIZE 48 +#define SCALAR_SIZE 32 +#define RANGE_PROOF_SIZE 1019 // needs to be at least 1019 +#define PRIVATE_KEY_SIZE 32 +#define TOKEN_ID_SIZE 40 // uint256 + uint64_t = 32 + 8 = 40 +#define UINT256_SIZE 32 +#define VIEW_TAG_SIZE 8 +#define UINT16_SIZE 2 +#define CTXOUT_BLSCT_DATA_SIZE \ + POINT_SIZE * 3 + \ + RANGE_PROOF_SIZE + \ + UINT16_SIZE +#define NORMAL_CSCRIPT_SIZE 1 +#define OP_SIZE 1 +#define STAKED_COMMITMENT_CSCRIPT_SIZE \ + OP_SIZE * 3 + \ + RANGE_PROOF_SIZE +#define CTXOUT_SIZE CAMOUNT_SIZE + \ + CSCRIPT_SIZE + \ + CTXOUT_BLSCT_DATA_SIZE + \ + TOKEN_ID_SIZE +#define UNSIGNED_OUTPUT_SIZE SCALAR_SIZE * 3 + CTXOUT_SIZE +#define OUT_POINT_SIZE 36 +#define SIGNATURE_SIZE 96 +#define SCRIPT_SIZE 28 +#define MEMO_BUF_SIZE 100 + +/* return codes */ +#define BLSCT_RESULT uint8_t +#define BLSCT_SUCCESS 0 +#define BLSCT_FAILURE 1 +#define BLSCT_EXCEPTION 2 +#define BLSCT_BAD_DPK_SIZE 10 +#define BLSCT_UNKNOWN_ENCODING 11 +#define BLSCT_VALUE_OUTSIDE_THE_RANGE 12 +#define BLSCT_DID_NOT_RUN_TO_COMPLETION 13 +#define BLSCT_BUFFER_TOO_SMALL 14 +#define BLSCT_IN_AMOUNT_ERROR 15 +#define BLSCT_OUT_AMOUNT_ERROR 16 +#define BLSCT_BAD_OUT_TYPE 17 +#define BLSCT_MEMO_TOO_LONG 18 + +#define TRY_DEFINE_MCL_POINT_FROM(src, dest) \ + Point dest; \ + if (!from_blsct_point_to_mcl_point(src, dest)) { \ + return BLSCT_FAILURE; \ + } + +#define TRY_DEFINE_MCL_SCALAR_FROM(src, dest) \ + Scalar dest; \ + from_blsct_scalar_to_mcl_scalar(src, dest) + +#define SERIALIZE_AND_COPY(src, dest) \ +{ \ + auto src_vec = src.GetVch(); \ + std::memcpy(dest, &src_vec[0], src_vec.size()); \ +} + +#define UNSERIALIZE_FROM_BYTE_ARRAY_WITH_STREAM(src, src_size, dest) \ +{ \ + Span buf(reinterpret_cast(src), src_size); \ + DataStream st{}; \ + st << buf; \ + dest.Unserialize(st); \ +} + +#define SERIALIZE_AND_COPY_WITH_STREAM(src, dest) \ +{ \ + DataStream st{}; \ + src.Serialize(st); \ + std::memcpy(dest, st.data(), st.size()); \ +} + +#define UNSERIALIZE_AND_COPY_WITH_STREAM(src, src_size, dest) \ +{ \ + DataStream st{}; \ + for (size_t i=0; i(new T); + +#define U8C(name, T) reinterpret_cast(const_cast(name)) + +#define VOID(T, name) reinterpret_cast(name) + +#define UNVOID(T, name) const T* name = reinterpret_cast(void_##name) + + +#ifdef __cplusplus extern "C" { +#endif + +enum Chain { + MainNet, + TestNet, + SigNet, + RegTest +}; + +enum TxOutputType { + Normal, + StakedCommitment +}; + +enum AddressEncoding { + Bech32, + Bech32M +}; + +using Point = Mcl::Point; +using Scalar = Mcl::Scalar; +using Scalars = Elements; + +typedef uint8_t BlsctKeyId[KEY_ID_SIZE]; // serialization of CKeyID which is based on uint160 +typedef uint8_t BlsctPoint[POINT_SIZE]; +typedef uint8_t BlsctPrivKey[PRIVATE_KEY_SIZE]; +typedef uint8_t BlsctPubKey[PUBLIC_KEY_SIZE]; +typedef uint8_t BlsctDoublePubKey[DOUBLE_PUBLIC_KEY_SIZE]; +typedef char BlsctAddrStr[ENCODED_DPK_STR_BUF_SIZE]; +typedef uint8_t BlsctRangeProof[RANGE_PROOF_SIZE]; +typedef uint8_t BlsctScalar[SCALAR_SIZE]; +typedef uint8_t BlsctSubAddr[SUBADDRESS_SIZE]; +typedef uint8_t BlsctSubAddrId[SUBADDRESS_ID_SIZE]; +typedef uint8_t BlsctTokenId[TOKEN_ID_SIZE]; +typedef uint8_t BlsctUint256[UINT256_SIZE]; +typedef uint8_t BlsctViewTag[VIEW_TAG_SIZE]; +typedef uint8_t BlsctOutPoint[OUT_POINT_SIZE]; +typedef uint8_t BlsctSignature[SIGNATURE_SIZE]; + +/* holds both request (in) and result (out) */ +typedef struct { + BlsctRangeProof range_proof; /* in */ + BlsctPoint nonce; /* in */ + bool is_succ; /* out */ + uint64_t amount; /* out */ + char msg[range_proof::Setup::max_message_size]; /* out */ + size_t msg_size; /* out */ +} BlsctAmountRecoveryRequest; + +typedef struct { + uint64_t amount; + uint64_t gamma; + BlsctScalar spending_key; + BlsctTokenId token_id; + BlsctOutPoint out_point; + bool rbf; +} BlsctTxIn; + +typedef struct { + BlsctSubAddr dest; + uint64_t amount; + char memo[MEMO_BUF_SIZE]; /* contains a c-str */ + BlsctTokenId token_id; + TxOutputType output_type; + uint64_t min_stake; +} BlsctTxOut; + +typedef struct { + uint8_t script[SCRIPT_SIZE]; + size_t size; +} BlsctScript; + +typedef struct { + BlsctPoint A; + BlsctPoint S; + BlsctPoint T1; + BlsctPoint T2; + BlsctScalar mu; + BlsctScalar tau_x; + + BlsctScalar a; + BlsctScalar b; + BlsctScalar t_hat; +} BlsctRangeProofDe; + +typedef struct { + BlsctPoint spending_key; + BlsctPoint ephemeral_key; + BlsctPoint blinding_key; + BlsctRangeProofDe range_proof; + uint16_t view_tag; +} BlsctBlsctData; + +typedef struct { + int64_t value; + BlsctScript script_pubkey; + BlsctBlsctData* blsct_data; + BlsctTokenId token_id; +} BlsctCTxOut; + +typedef struct { + BlsctUint256 hash; // Txid + uint32_t n; +} BlsctCOutPoint; + +typedef struct { + uint8_t* buf; + size_t size; +} BlsctVector; + +typedef struct { + BlsctVector* stack; + size_t size; +} BlsctScriptWitness; + +typedef struct { + BlsctCOutPoint prev_out; + BlsctScript script_sig; + uint32_t sequence; + BlsctScriptWitness script_witness; +} BlsctCTxIn; + +typedef struct { + int32_t version; + uint32_t lock_time; + BlsctSignature tx_sig; + BlsctCTxIn* ins; + size_t num_ins; + BlsctCTxOut* outs; + size_t num_outs; +} BlsctTransaction; + +typedef struct { + uint64_t token; + uint64_t subid; +} BlsctTokenIdDe; + +///// BEG new pointer-based API + +enum RetValType { + DecAddr, + DoublePubKey, + EncAddr, + TokenIdent, +}; + +/* value will not be set unless the result is BLSCT_SUCCESS */ +typedef struct { + RetValType type; + BLSCT_RESULT result; + void* value; +} BlsctRetVal; + +typedef struct { + BLSCT_RESULT result; + char* value; +} BlsctStrRetVal; + +typedef struct { + BLSCT_RESULT result; + bool value; +} BlsctBoolRetVal; + +typedef struct { + BLSCT_RESULT result; + BlsctRangeProof* value; +} BlsctRpRetVal; + +// library initialization +void init(); +bool set_chain(enum Chain chain); + +// point/scalar generation/disposition +BlsctPoint* gen_random_point(); +BlsctScalar* gen_random_scalar(); + +void dispose_point(BlsctPoint* blsct_point); +void dispose_scalar(BlsctScalar* blsct_scalar); +void dispose_public_key(BlsctPubKey* blsct_pub_key); + +BlsctScalar* gen_scalar(const uint64_t n); + +// type convertion +uint64_t scalar_to_uint64(BlsctScalar* blsct_scalar); + +// public key generation +BlsctPubKey* gen_random_public_key(); -void BlsctInit(); -void BlsctTest(); +BlsctRetVal* decode_address( + const char* blsct_enc_addr +); +BlsctStrRetVal* encode_address( + const void* void_blsct_dpk, + const enum AddressEncoding encoding +); + +BlsctRetVal* gen_double_pub_key( + const BlsctPubKey* blsct_pk1, + const BlsctPubKey* blsct_pk2 +); + +void dispose_double_pub_key( + const BlsctDoublePubKey* blsct_dpk +); + +BlsctRetVal* gen_token_id_with_subid( + const uint64_t token, + const uint64_t subid +); + +BlsctRetVal* gen_token_id( + const uint64_t token +); + +BlsctRetVal* gen_default_token_id(); + +void dispose_token_id(BlsctTokenId* blsct_token_id); + +BlsctRpRetVal* build_range_proof( + const void* vp_uint64_vs, + const size_t num_uint64_vs, + const BlsctPoint* blsct_nonce, + const char* blsct_message, + const size_t blsct_message_size, + const BlsctTokenId* blsct_token_id +); + +void dispose_range_proof(BlsctRangeProof* blsct_range_proof); + +BlsctBoolRetVal* verify_range_proofs( + const void* vp_range_proofs +); + +///// END new pointer-based API + +/* +void blsct_gen_out_point( + const char* tx_id_c_str, + const uint32_t n, + BlsctOutPoint blsct_out_point +); + +void blsct_uint64_to_blsct_uint256( + const uint64_t n, + BlsctUint256 uint256 +); + +// Point/Scalar generation functions + +bool blsct_is_valid_point(BlsctPoint blsct_point); + +bool blsct_from_point_to_blsct_point( + const Point& point, + BlsctPoint blsct_point +); + +// +// [in] src_str: source byte string +// [in] src_str_size: the size of the source byte string +// [out] public_key: randomly generated Public key +// +void blsct_hash_byte_str_to_public_key( + const char* src_str, + const size_t src_str_size, + BlsctPubKey blsct_pub_key +); + +void blsct_priv_key_to_pub_key( + const BlsctPrivKey blsct_priv_key, + BlsctPubKey blsct_pub_key +); + +void blsct_gen_dpk_with_keys_and_sub_addr_id( + const BlsctPrivKey blsct_view_key, + const BlsctPubKey blsct_spending_key, + const int64_t account, + const uint64_t address, + BlsctDoublePubKey dpk +); + +void blsct_dpk_to_sub_addr( + const BlsctDoublePubKey blsct_dpk, + BlsctSubAddr blsct_sub_addr +); + +// returns false and set uint64 max to token if token > uint64_t max +// +bool blsct_decode_token_id( + const BlsctTokenId blsct_token_id, + BlsctTokenIdDe* blsct_token_id_de +); + +// [out] blsct_priv_key +// +void blsct_gen_random_priv_key( + BlsctScalar blsct_priv_key +); + +// [in] byte string of size 32 +// [out] blsct_priv_key +// +void blsct_gen_priv_key( + const uint8_t priv_key[PRIVATE_KEY_SIZE], + BlsctScalar blsct_priv_key +); + +// attempts to recover all requests in the given request array +// and returns the recovery results in the same request array +// returns failure if exception is thrown and success otherwise +// +BLSCT_RESULT blsct_recover_amount( + BlsctAmountRecoveryRequest blsct_amount_recovery_reqs[], + const size_t num_reqs +); + +void blsct_sign_message( + const BlsctPrivKey blsct_priv_key, + const uint8_t* blsct_msg, + const size_t blsct_msg_size, + BlsctSignature blsct_signature +); + +bool blsct_verify_msg_sig( + const BlsctPubKey blsct_pub_key, + const uint8_t* blsct_msg, + const size_t blsct_msg_size, + const BlsctSignature blsct_signature +); + +void blsct_build_tx_in( + const uint64_t amount, + const uint64_t gamma, + const BlsctScalar spending_key, + const BlsctTokenId token_id, + const BlsctOutPoint out_point, + const bool rbf, + BlsctTxIn* const tx_in +); + +BLSCT_RESULT blsct_build_tx_out( + const BlsctSubAddr blsct_dest, + const uint64_t amount, + const char* memo, // should point to c-str + const BlsctTokenId blsct_token_id, + const TxOutputType output_type, + const uint64_t min_stake, + BlsctTxOut* const tx_out +); + +BLSCT_RESULT blsct_build_tx( + const BlsctTxIn blsct_tx_ins[], + const size_t num_blsct_tx_ins, + const BlsctTxOut blsct_tx_outs[], + const size_t num_blsct_tx_outs, + uint8_t* ser_tx, + size_t* ser_tx_size, // [in] size of serialized_tx buffer [out] size of the generated serialized tx + size_t* in_amount_err_index, // holds the first index of the tx_in whose amount exceeds the maximum + size_t* out_amount_err_index // holds the first index of the tx_out whose amount exceeds the maximum +); + +void blsct_deserialize_tx( + const uint8_t* ser_tx, + const size_t ser_tx_size, + BlsctTransaction** const blsct_tx +); + +void blsct_dispose_tx( + BlsctTransaction** const blsct_tx +); + +// helper functions to build a transaction + +// seed (scalar) +// +---> child key (scalar) +// +--------> blinding key (scalar) +// +--------> token key (scalar) +// +--------> tx key (scalar) +// +----> view key (scalar) +// +----> spending key (scalar) + +// key derivation functions + +// from seed +BLSCT_RESULT blsct_from_seed_to_child_key( + const BlsctScalar blsct_seed, + BlsctScalar blsct_child_key +); + +// from child_key +BLSCT_RESULT blsct_from_child_key_to_tx_key( + const BlsctScalar blsct_child_key, + BlsctScalar blsct_to_tx_key +); + +BLSCT_RESULT blsct_from_child_key_to_master_blinding_key( + const BlsctScalar blsct_child_key, + BlsctScalar blsct_master_blinding_key +); + +BLSCT_RESULT blsct_from_child_key_to_token_key( + const BlsctScalar blsct_child_key, + BlsctScalar blsct_token_key +); + +// from tx_key +BLSCT_RESULT blsct_from_tx_key_to_view_key( + const BlsctScalar blsct_tx_key, + BlsctPrivKey blsct_view_key +); + +BLSCT_RESULT blsct_from_tx_key_to_spending_key( + const BlsctScalar blsct_tx_key, + BlsctScalar blsct_spending_key +); + +BLSCT_RESULT blsct_calc_priv_spending_key( + const BlsctPoint blsct_blinding_pub_key, + const BlsctPoint blsct_spending_key, + const BlsctScalar blsct_view_key, + const int64_t& account, + const uint64_t& address, + BlsctScalar blsct_priv_spending_key +); + +BLSCT_RESULT blsct_derive_sub_addr( + const BlsctPrivKey blsct_view_key, + const BlsctPubKey blsct_spend_key, + const BlsctSubAddrId blsct_sub_addr_id, + BlsctSubAddr blsct_sub_addr +); + +BLSCT_RESULT blsct_calculate_nonce( + const BlsctPoint blsct_blinding_pub_key, + const BlsctScalar blsct_view_key, + BlsctPoint blect_nonce +); + +BLSCT_RESULT blsct_calculate_view_tag( + const BlsctPoint blinding_pub_key, + const BlsctScalar view_key, + BlsctViewTag blsct_view_tag +); + +BLSCT_RESULT blsct_calculate_hash_id( + const BlsctPoint blsct_blinding_pub_key, + const BlsctPoint blsct_spending_key, + const BlsctScalar blsct_view_key, + BlsctKeyId blsct_hash_id +); +*/ + +#ifdef __cplusplus } // extern "C" +#endif + +#endif // NAVCOIN_BLSCT_EXTERNAL_API_BLSCT_H + diff --git a/src/blsct/key_io.cpp b/src/blsct/key_io.cpp new file mode 100644 index 0000000000000..f1b05f2da1593 --- /dev/null +++ b/src/blsct/key_io.cpp @@ -0,0 +1,62 @@ +// Copyright (c) 2024 The Navcoin developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include +#include + +#include + +namespace blsct { + +std::string EncodeDoublePublicKey( + const std::string bech32_mod_hrp, + const bech32_mod::Encoding encoding, + const blsct::DoublePublicKey& dpk +) { + std::vector dpk_v8 = dpk.GetVch(); + std::vector 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, bech32_mod_hrp, dpk_v5); +} + +std::optional DecodeDoublePublicKey( + const std::string bech32_mod_hrp, + const std::string& str +) { + const auto hrp = ToLower(str.substr(0, bech32_mod_hrp.size())); + + // str needs to be of the expected length and have the expected hrp + if (str.size() != DOUBLE_PUBKEY_ENC_SIZE + || hrp != bech32_mod_hrp + || str[bech32_mod_hrp.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 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; + } +} + +} // namespace blsct diff --git a/src/blsct/key_io.h b/src/blsct/key_io.h new file mode 100644 index 0000000000000..8ae2bd74f9444 --- /dev/null +++ b/src/blsct/key_io.h @@ -0,0 +1,47 @@ +// Copyright (c) 2024 The Navcoin developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#ifndef NAVCOIN_BLSCT_KEY_IO_H +#define NAVCOIN_BLSCT_KEY_IO_H + +#include +#include +#include +#include + +namespace blsct { + +// ** COPIED FROM src/key_io.h ** +// +// 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; + +namespace bech32_hrp { + const std::string Main = "nv"; + const std::string TestNet = "tn"; + const std::string SigNet = "tn"; + const std::string RegTest = "nr"; +} + +/** Encode DoublePublicKey to Bech32 or Bech32m string. Encoding must be one of BECH32 or BECH32M. */ +std::string EncodeDoublePublicKey( + const std::string bech32_mod_hrp, + const bech32_mod::Encoding encoding, + const blsct::DoublePublicKey& dpk +); + +/** Decode a Bech32 or Bech32m string to a DoublePublicKey. */ +std::optional DecodeDoublePublicKey( + const std::string bech32_mod_hrp, + const std::string& str +); + +} // namespace blsct + +#endif // NAVCOIN_BLSCT_KEY_IO_H + diff --git a/src/blsct/pos/proof.cpp b/src/blsct/pos/proof.cpp index 3449ec4f6b990..17a44b4e7a246 100644 --- a/src/blsct/pos/proof.cpp +++ b/src/blsct/pos/proof.cpp @@ -119,4 +119,4 @@ uint256 ProofOfStake::CalculateMinValue(const uint256& kernel_hash, const unsign if (next_target == 0) return uint256(); return ArithToUint256(UintToArith256(kernel_hash) / arith_uint256().SetCompact(next_target)); } -} // namespace blsct \ No newline at end of file +} // namespace blsct diff --git a/src/blsct/public_key.cpp b/src/blsct/public_key.cpp index 523f76bbdf5d7..22ec308bd6d66 100644 --- a/src/blsct/public_key.cpp +++ b/src/blsct/public_key.cpp @@ -56,6 +56,11 @@ std::vector PublicKey::GetVch() const return point.GetVch(); } +bool PublicKey::SetVch(const std::vector vec) +{ + return point.SetVch(vec); +} + blsPublicKey PublicKey::ToBlsPublicKey() const { blsPublicKey bls_pk{point.GetUnderlying()}; diff --git a/src/blsct/public_key.h b/src/blsct/public_key.h index 3f26f78339962..fcaf49e050687 100644 --- a/src/blsct/public_key.h +++ b/src/blsct/public_key.h @@ -56,6 +56,7 @@ class PublicKey Point GetG1Point() const; std::vector GetVch() const; + bool SetVch(const std::vector vec); bool operator<(const PublicKey& b) const { diff --git a/src/key_io.cpp b/src/key_io.cpp index 1d892ee967b87..015e37de98cd3 100644 --- a/src/key_io.cpp +++ b/src/key_io.cpp @@ -7,6 +7,7 @@ #include #include #include +#include #include #include #include