From 983dc27023710763f0dd5bc5fffac2257662e3d3 Mon Sep 17 00:00:00 2001 From: levonpetrosyan93 <45027856+levonpetrosyan93@users.noreply.github.com> Date: Sun, 12 Jan 2025 16:06:45 +0400 Subject: [PATCH] Libspats cleanup refacor (#1517) * Cleanup and refactor * More cleanup * Reverted some changes, bug fixes * More fixes --- src/Makefile.am | 28 +- src/Makefile.test.include | 48 +- src/libspark/coin.cpp | 2 +- src/libspark/grootle.h | 2 +- src/libspark/params.cpp | 30 + src/libspark/params.h | 10 +- src/libspark/spend_transaction.cpp | 2 +- src/libspark/util.h | 7 + src/libspats/aead.cpp | 92 --- src/libspats/aead.h | 31 - src/libspats/balance.cpp | 5 +- src/libspats/balance_proof.h | 2 +- src/libspats/base_asset.cpp | 5 +- src/libspats/base_asset_proof.h | 2 +- src/libspats/bech32.cpp | 248 -------- src/libspats/bech32.h | 63 -- src/libspats/bpplus.cpp | 53 +- src/libspats/bpplus_proof.h | 2 +- src/libspats/chaum.cpp | 176 ------ src/libspats/chaum.h | 45 -- src/libspats/chaum_proof.h | 32 -- src/libspats/coin.cpp | 64 ++- src/libspats/coin.h | 32 +- src/libspats/f4grumble.cpp | 152 ----- src/libspats/f4grumble.h | 32 -- src/libspats/grootle.cpp | 573 ------------------- src/libspats/grootle.h | 56 -- src/libspats/grootle_proof.h | 45 -- src/libspats/hash.cpp | 160 ------ src/libspats/hash.h | 26 - src/libspats/kdf.cpp | 58 -- src/libspats/kdf.h | 23 - src/libspats/keys.cpp | 246 -------- src/libspats/keys.h | 95 --- src/libspats/mint_transaction.cpp | 16 +- src/libspats/mint_transaction.h | 14 +- src/libspats/params.cpp | 164 ------ src/libspats/params.h | 75 --- src/libspats/schnorr.cpp | 99 ---- src/libspats/schnorr.h | 25 - src/libspats/schnorr_proof.h | 27 - src/libspats/spend_transaction.cpp | 126 ++-- src/libspats/spend_transaction.h | 47 +- src/libspats/test/coin_test.cpp | 39 +- src/libspats/test/mint_transaction_test.cpp | 24 +- src/libspats/test/spend_transaction_test.cpp | 14 +- src/libspats/test/tasty.cpp | 2 +- src/libspats/transcript.cpp | 177 ------ src/libspats/transcript.h | 32 -- src/libspats/type.cpp | 28 +- src/libspats/type_proof.h | 2 +- src/libspats/util.cpp | 249 -------- src/libspats/util.h | 96 +--- src/wallet.backup | 8 - 54 files changed, 337 insertions(+), 3374 deletions(-) delete mode 100644 src/libspats/aead.cpp delete mode 100644 src/libspats/aead.h delete mode 100644 src/libspats/bech32.cpp delete mode 100644 src/libspats/bech32.h delete mode 100644 src/libspats/chaum.cpp delete mode 100644 src/libspats/chaum.h delete mode 100644 src/libspats/chaum_proof.h delete mode 100644 src/libspats/f4grumble.cpp delete mode 100644 src/libspats/f4grumble.h delete mode 100644 src/libspats/grootle.cpp delete mode 100644 src/libspats/grootle.h delete mode 100644 src/libspats/grootle_proof.h delete mode 100644 src/libspats/hash.cpp delete mode 100644 src/libspats/hash.h delete mode 100644 src/libspats/kdf.cpp delete mode 100644 src/libspats/kdf.h delete mode 100644 src/libspats/keys.cpp delete mode 100644 src/libspats/keys.h delete mode 100644 src/libspats/params.cpp delete mode 100644 src/libspats/params.h delete mode 100644 src/libspats/schnorr.cpp delete mode 100644 src/libspats/schnorr.h delete mode 100644 src/libspats/schnorr_proof.h delete mode 100644 src/libspats/transcript.cpp delete mode 100644 src/libspats/transcript.h delete mode 100644 src/libspats/util.cpp delete mode 100644 src/wallet.backup diff --git a/src/Makefile.am b/src/Makefile.am index beec70aa85..369349a33a 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -56,6 +56,7 @@ LIBBITCOIN_CLI=libbitcoin_cli.a LIBBITCOIN_UTIL=libbitcoin_util.a LIBLELANTUS=liblelantus.a LIBSPARK=libspark.a +LIBSPATS=libspats.a LIBBITCOIN_CRYPTO=crypto/libbitcoin_crypto.a LIBBITCOINQT=qt/libfiroqt.a LIBSECP256K1=secp256k1/libsecp256k1.la @@ -88,7 +89,8 @@ EXTRA_LIBRARIES += \ $(LIBBITCOIN_ZMQ) \ $(LIBFIRO_SIGMA) \ $(LIBLELANTUS) \ - $(LIBSPARK) + $(LIBSPARK) \ + $(LIBSPATS) lib_LTLIBRARIES = $(LIBBITCOINCONSENSUS) @@ -693,6 +695,29 @@ libspark_a_SOURCES = \ libspark/bech32.h \ libspark/bech32.cpp +libspats_a_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) +libspats_a_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) +libspats_a_SOURCES = \ + libspats/bpplus.cpp \ + libspats/bpplus.h \ + libspats/bpplus_proof.h \ + libspats/coin.cpp \ + libspats/coin.h \ + libspats/base_asset.h \ + libspats/base_asset.cpp \ + libspats/base_asset_proof.h \ + libspats/type_proof.h \ + libspats/type.cpp \ + libspats/type.h \ + libspats/balance.h \ + libspats/balance.cpp \ + libspats/balance_proof.h \ + libspats/mint_transaction.cpp \ + libspats/mint_transaction.h \ + libspats/spend_transaction.cpp \ + libspats/spend_transaction.h \ + libspats/util.h + liblelantus_a_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) liblelantus_a_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) liblelantus_a_SOURCES = \ @@ -799,6 +824,7 @@ firod_LDADD = \ $(LIBFIRO_SIGMA) \ $(LIBLELANTUS) \ $(LIBSPARK) \ + $(LIBSPATS) \ $(LIBBITCOIN_ZMQ) \ $(LIBBITCOIN_CONSENSUS) \ $(LIBBITCOIN_CRYPTO) \ diff --git a/src/Makefile.test.include b/src/Makefile.test.include index 079457994f..0e8393caf0 100644 --- a/src/Makefile.test.include +++ b/src/Makefile.test.include @@ -197,51 +197,6 @@ BITCOIN_TESTS = \ test/evo_simplifiedmns_tests.cpp \ test/progpow_tests.cpp \ test/bls_tests.cpp \ - libspats/aead.cpp \ - libspats/aead.h \ - libspats/bech32.cpp \ - libspats/bech32.h \ - libspats/bpplus.cpp \ - libspats/bpplus.h \ - libspats/bpplus_proof.h \ - libspats/chaum.cpp \ - libspats/chaum.h \ - libspats/chaum_proof.h \ - libspats/coin.cpp \ - libspats/coin.h \ - libspats/f4grumble.cpp \ - libspats/f4grumble.h \ - libspats/grootle.cpp \ - libspats/grootle.h \ - libspats/grootle_proof.h \ - libspats/hash.cpp \ - libspats/hash.h \ - libspats/kdf.cpp \ - libspats/kdf.h \ - libspats/keys.cpp \ - libspats/keys.h \ - libspats/base_asset.h \ - libspats/base_asset.cpp \ - libspats/base_asset_proof.h \ - libspats/type_proof.h \ - libspats/type.cpp \ - libspats/type.h \ - libspats/balance.h \ - libspats/balance.cpp \ - libspats/balance_proof.h \ - libspats/mint_transaction.cpp \ - libspats/mint_transaction.h \ - libspats/params.cpp \ - libspats/params.h \ - libspats/schnorr.cpp \ - libspats/schnorr.h \ - libspats/schnorr_proof.h \ - libspats/spend_transaction.cpp \ - libspats/spend_transaction.h \ - libspats/transcript.cpp \ - libspats/transcript.h \ - libspats/util.cpp \ - libspats/util.h \ libspats/test/bpplus_test.cpp \ libspats/test/coin_test.cpp \ libspats/test/type_test.cpp \ @@ -269,7 +224,7 @@ test_test_bitcoin_LDADD = $(LIBBITCOIN_SERVER) -ltor test_test_bitcoin_SOURCES = $(BITCOIN_TESTS) $(JSON_TEST_FILES) $(RAW_TEST_FILES) test_test_bitcoin_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) -I$(builddir)/test/ $(TESTDEFS) $(EVENT_CFLAGS) -test_test_bitcoin_LDADD += $(LIBBITCOIN_CLI) $(LIBBITCOIN_COMMON) $(LIBBITCOIN_UTIL) $(LIBBITCOIN_CONSENSUS) $(LIBBITCOIN_CRYPTO) $(LIBFIRO_SIGMA) $(LIBLELANTUS) $(LIBSPARK) $(LIBUNIVALUE) $(LIBLEVELDB) $(LIBLEVELDB_SSE42) $(LIBMEMENV) \ +test_test_bitcoin_LDADD += $(LIBBITCOIN_CLI) $(LIBBITCOIN_COMMON) $(LIBBITCOIN_UTIL) $(LIBBITCOIN_CONSENSUS) $(LIBBITCOIN_CRYPTO) $(LIBFIRO_SIGMA) $(LIBLELANTUS) $(LIBSPARK) $(LIBSPATS) $(LIBUNIVALUE) $(LIBLEVELDB) $(LIBLEVELDB_SSE42) $(LIBMEMENV) \ $(BACKTRACE_LIB) $(BOOST_LIBS) $(BOOST_UNIT_TEST_FRAMEWORK_LIB) $(LIBSECP256K1) $(EVENT_PTHREADS_LIBS) $(ZMQ_LIBS) $(ZLIB_LIBS) test_test_bitcoin_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) if ENABLE_WALLET @@ -297,6 +252,7 @@ test_test_bitcoin_fuzzy_LDADD = \ $(LIBBITCOIN_SERVER) \ $(LIBLELANTUS) \ $(LIBSPARK) \ + $(LIBSPATS) \ $(LIBBITCOIN_COMMON) \ $(LIBBITCOIN_UTIL) \ $(LIBBITCOIN_CONSENSUS) \ diff --git a/src/libspark/coin.cpp b/src/libspark/coin.cpp index b7d87fd89b..ed53f2d69b 100644 --- a/src/libspark/coin.cpp +++ b/src/libspark/coin.cpp @@ -112,7 +112,7 @@ bool Coin::validate( // Recover a coin RecoveredCoinData Coin::recover(const FullViewKey& full_view_key, const IdentifiedCoinData& data) { RecoveredCoinData recovered_data; - recovered_data.s = SparkUtils::hash_ser(data.k, this->serial_context) + SparkUtils::hash_Q2(full_view_key.get_s1(), data.i) + full_view_key.get_s2(); + recovered_data.s = SparkUtils::hash_ser(data.k, this->serial_context) + SparkUtils::hash_Q2(full_view_key.get_s1(), data.i) + full_view_key.get_s2(); recovered_data.T = (this->params->get_U() + full_view_key.get_D().inverse())*recovered_data.s.inverse(); return recovered_data; diff --git a/src/libspark/grootle.h b/src/libspark/grootle.h index f0d5dd4b27..acb171e7f7 100644 --- a/src/libspark/grootle.h +++ b/src/libspark/grootle.h @@ -17,7 +17,7 @@ class Grootle { const std::vector& Hi, const std::size_t n, const std::size_t m - ); + ); void prove(const std::size_t l, const Scalar& s, diff --git a/src/libspark/params.cpp b/src/libspark/params.cpp index b36280fb28..b963ee7066 100644 --- a/src/libspark/params.cpp +++ b/src/libspark/params.cpp @@ -55,6 +55,7 @@ Params::Params( ) { // Global generators + this->E = SparkUtils::hash_generator(LABEL_GENERATOR_E); this->F = SparkUtils::hash_generator(LABEL_GENERATOR_F); this->G.set_base_g(); this->H = SparkUtils::hash_generator(LABEL_GENERATOR_H); @@ -65,9 +66,13 @@ Params::Params( // Range proof parameters this->max_M_range = max_M_range; + this->E_range.resize(64*max_M_range); + this->F_range.resize(64*max_M_range); this->G_range.resize(64*max_M_range); this->H_range.resize(64*max_M_range); for (std::size_t i = 0; i < 64*max_M_range; i++) { + this->E_range[i] = SparkUtils::hash_generator(LABEL_GENERATOR_E_RANGE + " " + std::to_string(i)); + this->F_range[i] = SparkUtils::hash_generator(LABEL_GENERATOR_F_RANGE + " " + std::to_string(i)); this->G_range[i] = SparkUtils::hash_generator(LABEL_GENERATOR_G_RANGE + " " + std::to_string(i)); this->H_range[i] = SparkUtils::hash_generator(LABEL_GENERATOR_H_RANGE + " " + std::to_string(i)); } @@ -78,9 +83,13 @@ Params::Params( } this->n_grootle = n_grootle; this->m_grootle = m_grootle; + this->E_grootle.resize(n_grootle * m_grootle); + this->F_grootle.resize(n_grootle * m_grootle); this->G_grootle.resize(n_grootle * m_grootle); this->H_grootle.resize(n_grootle * m_grootle); for (std::size_t i = 0; i < n_grootle * m_grootle; i++) { + this->E_grootle[i] = SparkUtils::hash_generator(LABEL_GENERATOR_E_GROOTLE + " " + std::to_string(i)); + this->F_grootle[i] = SparkUtils::hash_generator(LABEL_GENERATOR_F_GROOTLE + " " + std::to_string(i)); this->G_grootle[i] = SparkUtils::hash_generator(LABEL_GENERATOR_G_GROOTLE + " " + std::to_string(i)); this->H_grootle[i] = SparkUtils::hash_generator(LABEL_GENERATOR_H_GROOTLE + " " + std::to_string(i)); } @@ -102,10 +111,22 @@ const GroupElement& Params::get_U() const { return this->U; } +const GroupElement& Params::get_E() const { + return this->E; +} + const std::size_t Params::get_memo_bytes() const { return this->memo_bytes; } +const std::vector& Params::get_E_range() const { + return this->E_range; +} + +const std::vector& Params::get_F_range() const { + return this->F_range; +} + const std::vector& Params::get_G_range() const { return this->G_range; } @@ -114,10 +135,19 @@ const std::vector& Params::get_H_range() const { return this->H_range; } +const std::vector& Params::get_E_grootle() const { + return this->E_grootle; +} + const std::vector& Params::get_G_grootle() const { return this->G_grootle; } + +const std::vector& Params::get_F_grootle() const { + return this->F_grootle; +} + const std::vector& Params::get_H_grootle() const { return this->H_grootle; } diff --git a/src/libspark/params.h b/src/libspark/params.h index 3b18f18ad5..b3f1858489 100644 --- a/src/libspark/params.h +++ b/src/libspark/params.h @@ -19,15 +19,20 @@ class Params { const GroupElement& get_G() const; const GroupElement& get_H() const; const GroupElement& get_U() const; + const GroupElement& get_E() const; const std::size_t get_memo_bytes() const; std::size_t get_max_M_range() const; + const std::vector& get_E_range() const; + const std::vector& get_F_range() const; const std::vector& get_G_range() const; const std::vector& get_H_range() const; std::size_t get_n_grootle() const; std::size_t get_m_grootle() const; + const std::vector& get_E_grootle() const; + const std::vector& get_F_grootle() const; const std::vector& get_G_grootle() const; const std::vector& get_H_grootle() const; @@ -44,6 +49,7 @@ class Params { static std::unique_ptr instance; // Global generators + GroupElement E; GroupElement F; GroupElement G; GroupElement H; @@ -54,12 +60,14 @@ class Params { // Range proof parameters std::size_t max_M_range; - std::vector G_range, H_range; + std::vector G_range, H_range, E_range, F_range; // One-of-many parameters std::size_t n_grootle, m_grootle; std::vector G_grootle; std::vector H_grootle; + std::vector E_grootle; + std::vector F_grootle; }; } diff --git a/src/libspark/spend_transaction.cpp b/src/libspark/spend_transaction.cpp index 3e30b64a4c..95573102e1 100644 --- a/src/libspark/spend_transaction.cpp +++ b/src/libspark/spend_transaction.cpp @@ -359,7 +359,7 @@ bool SpendTransaction::verify( params->get_H_grootle(), params->get_n_grootle(), params->get_m_grootle() - ); + ); for (auto grootle_bucket : grootle_buckets) { std::size_t cover_set_id = grootle_bucket.first; std::vector> proof_indexes = grootle_bucket.second; diff --git a/src/libspark/util.h b/src/libspark/util.h index 19b8c9298b..b50769dc93 100644 --- a/src/libspark/util.h +++ b/src/libspark/util.h @@ -41,6 +41,13 @@ const std::string LABEL_GENERATOR_H_RANGE = "H_RANGE"; const std::string LABEL_GENERATOR_G_GROOTLE = "G_GROOTLE"; const std::string LABEL_GENERATOR_H_GROOTLE = "H_GROOTLE"; +// Spark assets Generator labels +const std::string LABEL_GENERATOR_E = "E"; +const std::string LABEL_GENERATOR_E_RANGE = "E_RANGE"; +const std::string LABEL_GENERATOR_F_RANGE = "F_RANGE"; +const std::string LABEL_GENERATOR_E_GROOTLE = "E_GROOTLE"; +const std::string LABEL_GENERATOR_F_GROOTLE = "F_GROOTLE"; + // Hash function labels const std::string LABEL_HASH_DIV = "DIV"; const std::string LABEL_HASH_Q2 = "Q2"; diff --git a/src/libspats/aead.cpp b/src/libspats/aead.cpp deleted file mode 100644 index 8b8e3f355a..0000000000 --- a/src/libspats/aead.cpp +++ /dev/null @@ -1,92 +0,0 @@ -#include "aead.h" - -namespace spats { - -// Perform authenticated encryption with ChaCha20-Poly1305 using key commitment -AEADEncryptedData AEAD::encrypt(const GroupElement& prekey, const std::string additional_data, CDataStream& data) { - // Set up the result structure - AEADEncryptedData result; - - // Derive the key and commitment - std::vector key = SpatsUtils::kdf_aead(prekey); - result.key_commitment = SpatsUtils::commit_aead(prekey); - - // Internal size tracker; we know the size of the data already, and can ignore - int TEMP; - - // For our application, we can safely use a zero nonce since keys are never reused - std::vector iv; - iv.resize(AEAD_IV_SIZE); - - // Set up the cipher - EVP_CIPHER_CTX* ctx; - ctx = EVP_CIPHER_CTX_new(); - EVP_EncryptInit_ex(ctx, EVP_chacha20_poly1305(), NULL, key.data(), iv.data()); - - // Include the associated data - std::vector additional_data_bytes(additional_data.begin(), additional_data.end()); - EVP_EncryptUpdate(ctx, NULL, &TEMP, additional_data_bytes.data(), additional_data_bytes.size()); - - // Encrypt the plaintext - result.ciphertext.resize(data.size()); - EVP_EncryptUpdate(ctx, result.ciphertext.data(), &TEMP, reinterpret_cast(data.data()), data.size()); - EVP_EncryptFinal_ex(ctx, NULL, &TEMP); - - // Get the tag - result.tag.resize(AEAD_TAG_SIZE); - EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_GET_TAG, AEAD_TAG_SIZE, result.tag.data()); - - // Clean up - EVP_CIPHER_CTX_free(ctx); - - return result; -} - -// Perform authenticated decryption with ChaCha20-Poly1305 using key commitment -CDataStream AEAD::decrypt_and_verify(const GroupElement& prekey, const std::string additional_data, AEADEncryptedData& data) { - // Derive the key and commitment - std::vector key = SpatsUtils::kdf_aead(prekey); - std::vector key_commitment = SpatsUtils::commit_aead(prekey); - - // Assert that the key commitment is valid - if (key_commitment != data.key_commitment) { - throw std::runtime_error("Bad AEAD key commitment"); - } - - // Set up the result - CDataStream result(SER_NETWORK, PROTOCOL_VERSION); - - // Internal size tracker; we know the size of the data already, and can ignore - int TEMP; - - // For our application, we can safely use a zero nonce since keys are never reused - std::vector iv; - iv.resize(AEAD_IV_SIZE); - - // Set up the cipher - EVP_CIPHER_CTX* ctx; - ctx = EVP_CIPHER_CTX_new(); - EVP_DecryptInit_ex(ctx, EVP_chacha20_poly1305(), NULL, key.data(), iv.data()); - - // Include the associated data - std::vector additional_data_bytes(additional_data.begin(), additional_data.end()); - EVP_DecryptUpdate(ctx, NULL, &TEMP, additional_data_bytes.data(), additional_data_bytes.size()); - - // Decrypt the ciphertext - result.resize(data.ciphertext.size()); - EVP_DecryptUpdate(ctx, reinterpret_cast(result.data()), &TEMP, data.ciphertext.data(), data.ciphertext.size()); - - // Set the expected tag - EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_SET_TAG, AEAD_TAG_SIZE, data.tag.data()); - - // Decrypt and clean up - int ret = EVP_DecryptFinal_ex(ctx, NULL, &TEMP); - EVP_CIPHER_CTX_free(ctx); - if (ret != 1) { - throw std::runtime_error("Bad AEAD authentication"); - } - - return result; -} - -} diff --git a/src/libspats/aead.h b/src/libspats/aead.h deleted file mode 100644 index b8155b12dc..0000000000 --- a/src/libspats/aead.h +++ /dev/null @@ -1,31 +0,0 @@ -#ifndef FIRO_SPATS_AEAD_H -#define FIRO_SPATS_AEAD_H -#include -#include "util.h" - -namespace spats { - -struct AEADEncryptedData { - std::vector ciphertext; - std::vector tag; - std::vector key_commitment; - - ADD_SERIALIZE_METHODS; - - template - inline void SerializationOp(Stream& s, Operation ser_action) { - READWRITE(ciphertext); - READWRITE(tag); - READWRITE(key_commitment); - } -}; - -class AEAD { -public: - static AEADEncryptedData encrypt(const GroupElement& prekey, const std::string additional_data, CDataStream& data); - static CDataStream decrypt_and_verify(const GroupElement& prekey, const std::string associated_data, AEADEncryptedData& data); -}; - -} - -#endif diff --git a/src/libspats/balance.cpp b/src/libspats/balance.cpp index 7e6333f84f..8b1cb500c7 100644 --- a/src/libspats/balance.cpp +++ b/src/libspats/balance.cpp @@ -1,5 +1,6 @@ #include "balance.h" -#include "transcript.h" +#include "../libspark/transcript.h" +#include "util.h" namespace spats { @@ -12,7 +13,7 @@ Scalar Balance::challenge( const GroupElement& C, const GroupElement& A) { - Transcript transcript(LABEL_TRANSCRIPT_BALANCE); + spark::Transcript transcript(LABEL_TRANSCRIPT_BALANCE); transcript.add("E", E); transcript.add("F", F); transcript.add("H", H); diff --git a/src/libspats/balance_proof.h b/src/libspats/balance_proof.h index 86963e5958..de882a61fb 100644 --- a/src/libspats/balance_proof.h +++ b/src/libspats/balance_proof.h @@ -1,7 +1,7 @@ #ifndef FIRO_LIBSPATS_BALANCE_PROOF_H #define FIRO_LIBSPATS_BALANCE_PROOF_H -#include "params.h" +#include "../libspark/params.h" namespace spats{ diff --git a/src/libspats/base_asset.cpp b/src/libspats/base_asset.cpp index 5b81bb6dba..399883e8f8 100644 --- a/src/libspats/base_asset.cpp +++ b/src/libspats/base_asset.cpp @@ -1,5 +1,6 @@ #include "base_asset.h" -#include "transcript.h" +#include "../libspark/transcript.h" +#include "util.h" namespace spats { @@ -12,7 +13,7 @@ Scalar BaseAsset::challenge( const std::vector& C, const GroupElement& A) { - Transcript transcript(LABEL_TRANSCRIPT_BASE); + spark::Transcript transcript(LABEL_TRANSCRIPT_BASE); transcript.add("G", G); transcript.add("H", H); transcript.add("C", C); diff --git a/src/libspats/base_asset_proof.h b/src/libspats/base_asset_proof.h index 0f9274fc0f..a00ee55fca 100644 --- a/src/libspats/base_asset_proof.h +++ b/src/libspats/base_asset_proof.h @@ -1,7 +1,7 @@ #ifndef FIRO_LIBSPATS_BASE_PROOF_H #define FIRO_LIBSPATS_BASE_PROOF_H -#include "params.h" +#include "../libspark/params.h" namespace spats { diff --git a/src/libspats/bech32.cpp b/src/libspats/bech32.cpp deleted file mode 100644 index 67b76c726b..0000000000 --- a/src/libspats/bech32.cpp +++ /dev/null @@ -1,248 +0,0 @@ -/* Copyright (c) 2017, 2021 Pieter Wuille - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -// Copyright (c) 2017 Pieter Wuille -// Distributed under the MIT software license, see the accompanying -// file COPYING or http://www.opensource.org/licenses/mit-license.php. - -#include "bech32.h" - -#include -#include - -#include -#include - -namespace bech32 -{ - -namespace -{ - -typedef std::vector data; - -/** The Bech32 character set for encoding. */ -const char* CHARSET = "qpzry9x8gf2tvdw0s3jn54khce6mua7l"; - -/** The Bech32 character set for decoding. */ -const int8_t CHARSET_REV[128] = { - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - 15, -1, 10, 17, 21, 20, 26, 30, 7, 5, -1, -1, -1, -1, -1, -1, - -1, 29, -1, 24, 13, 25, 9, 8, 23, -1, 18, 22, 31, 27, 19, -1, - 1, 0, 3, 16, 11, 28, 12, 14, 6, 4, 2, -1, -1, -1, -1, -1, - -1, 29, -1, 24, 13, 25, 9, 8, 23, -1, 18, 22, 31, 27, 19, -1, - 1, 0, 3, 16, 11, 28, 12, 14, 6, 4, 2, -1, -1, -1, -1, -1 -}; - -/** Concatenate two byte arrays. */ -data cat(data x, const data& y) { - x.insert(x.end(), y.begin(), y.end()); - return x; -} - -/* Determine the final constant to use for the specified encoding. */ -uint32_t encoding_constant(Encoding encoding) { - assert(encoding == Encoding::BECH32 || encoding == Encoding::BECH32M); - return encoding == Encoding::BECH32 ? 1 : 0x2bc830a3; -} - -/** This function will compute what 6 5-bit values to XOR into the last 6 input values, in order to - * make the checksum 0. These 6 values are packed together in a single 30-bit integer. The higher - * bits correspond to earlier values. */ -uint32_t polymod(const data& values) -{ - // The input is interpreted as a list of coefficients of a polynomial over F = GF(32), with an - // implicit 1 in front. If the input is [v0,v1,v2,v3,v4], that polynomial is v(x) = - // 1*x^5 + v0*x^4 + v1*x^3 + v2*x^2 + v3*x + v4. The implicit 1 guarantees that - // [v0,v1,v2,...] has a distinct checksum from [0,v0,v1,v2,...]. - - // The output is a 30-bit integer whose 5-bit groups are the coefficients of the remainder of - // v(x) mod g(x), where g(x) is the Bech32 generator, - // x^6 + {29}x^5 + {22}x^4 + {20}x^3 + {21}x^2 + {29}x + {18}. g(x) is chosen in such a way - // that the resulting code is a BCH code, guaranteeing detection of up to 3 errors within a - // window of 1023 characters. Among the various possible BCH codes, one was selected to in - // fact guarantee detection of up to 4 errors within a window of 89 characters. - - // Note that the coefficients are elements of GF(32), here represented as decimal numbers - // between {}. In this finite field, addition is just XOR of the corresponding numbers. For - // example, {27} + {13} = {27 ^ 13} = {22}. Multiplication is more complicated, and requires - // treating the bits of values themselves as coefficients of a polynomial over a smaller field, - // GF(2), and multiplying those polynomials mod a^5 + a^3 + 1. For example, {5} * {26} = - // (a^2 + 1) * (a^4 + a^3 + a) = (a^4 + a^3 + a) * a^2 + (a^4 + a^3 + a) = a^6 + a^5 + a^4 + a - // = a^3 + 1 (mod a^5 + a^3 + 1) = {9}. - - // During the course of the loop below, `c` contains the bitpacked coefficients of the - // polynomial constructed from just the values of v that were processed so far, mod g(x). In - // the above example, `c` initially corresponds to 1 mod g(x), and after processing 2 inputs of - // v, it corresponds to x^2 + v0*x + v1 mod g(x). As 1 mod g(x) = 1, that is the starting value - // for `c`. - uint32_t c = 1; - for (const auto v_i : values) { - // We want to update `c` to correspond to a polynomial with one extra term. If the initial - // value of `c` consists of the coefficients of c(x) = f(x) mod g(x), we modify it to - // correspond to c'(x) = (f(x) * x + v_i) mod g(x), where v_i is the next input to - // process. Simplifying: - // c'(x) = (f(x) * x + v_i) mod g(x) - // ((f(x) mod g(x)) * x + v_i) mod g(x) - // (c(x) * x + v_i) mod g(x) - // If c(x) = c0*x^5 + c1*x^4 + c2*x^3 + c3*x^2 + c4*x + c5, we want to compute - // c'(x) = (c0*x^5 + c1*x^4 + c2*x^3 + c3*x^2 + c4*x + c5) * x + v_i mod g(x) - // = c0*x^6 + c1*x^5 + c2*x^4 + c3*x^3 + c4*x^2 + c5*x + v_i mod g(x) - // = c0*(x^6 mod g(x)) + c1*x^5 + c2*x^4 + c3*x^3 + c4*x^2 + c5*x + v_i - // If we call (x^6 mod g(x)) = k(x), this can be written as - // c'(x) = (c1*x^5 + c2*x^4 + c3*x^3 + c4*x^2 + c5*x + v_i) + c0*k(x) - - // First, determine the value of c0: - uint8_t c0 = c >> 25; - - // Then compute c1*x^5 + c2*x^4 + c3*x^3 + c4*x^2 + c5*x + v_i: - c = ((c & 0x1ffffff) << 5) ^ v_i; - - // Finally, for each set bit n in c0, conditionally add {2^n}k(x): - if (c0 & 1) c ^= 0x3b6a57b2; // k(x) = {29}x^5 + {22}x^4 + {20}x^3 + {21}x^2 + {29}x + {18} - if (c0 & 2) c ^= 0x26508e6d; // {2}k(x) = {19}x^5 + {5}x^4 + x^3 + {3}x^2 + {19}x + {13} - if (c0 & 4) c ^= 0x1ea119fa; // {4}k(x) = {15}x^5 + {10}x^4 + {2}x^3 + {6}x^2 + {15}x + {26} - if (c0 & 8) c ^= 0x3d4233dd; // {8}k(x) = {30}x^5 + {20}x^4 + {4}x^3 + {12}x^2 + {30}x + {29} - if (c0 & 16) c ^= 0x2a1462b3; // {16}k(x) = {21}x^5 + x^4 + {8}x^3 + {24}x^2 + {21}x + {19} - } - return c; -} - -/** Convert to lower case. */ -unsigned char lc(unsigned char c) { - return (c >= 'A' && c <= 'Z') ? (c - 'A') + 'a' : c; -} - -/** Expand a HRP for use in checksum computation. */ -data expand_hrp(const std::string& hrp) { - data ret; - ret.resize(hrp.size() * 2 + 1); - for (size_t i = 0; i < hrp.size(); ++i) { - unsigned char c = hrp[i]; - ret[i] = c >> 5; - ret[i + hrp.size() + 1] = c & 0x1f; - } - ret[hrp.size()] = 0; - return ret; -} - -/** Verify a checksum. */ -Encoding verify_checksum(const std::string& hrp, const data& values) { - // PolyMod computes what value to xor into the final values to make the checksum 0. However, - // if we required that the checksum was 0, it would be the case that appending a 0 to a valid - // list of values would result in a new valid list. For that reason, Bech32 requires the - // resulting checksum to be 1 instead. In Bech32m, this constant was amended. - uint32_t check = polymod(cat(expand_hrp(hrp), values)); - if (check == encoding_constant(Encoding::BECH32)) return Encoding::BECH32; - if (check == encoding_constant(Encoding::BECH32M)) return Encoding::BECH32M; - return Encoding::INVALID; -} - -data create_checksum(const std::string& hrp, const data& values, Encoding encoding) { - data enc = cat(expand_hrp(hrp), values); - enc.resize(enc.size() + 6); - uint32_t mod = polymod(enc) ^ encoding_constant(encoding); - data ret; - ret.resize(6); - for (size_t i = 0; i < 6; ++i) { - // Convert the 5-bit groups in mod to checksum values. - ret[i] = (mod >> (5 * (5 - i))) & 31; - } - return ret; -} - -} // namespace - -/** Encode a Bech32 or Bech32m string. */ -std::string encode(const std::string& hrp, const data& values, Encoding encoding) { - // First ensure that the HRP is all lowercase. BIP-173 requires an encoder - // to return a lowercase Bech32 string, but if given an uppercase HRP, the - // result will always be invalid. - for (const char& c : hrp) assert(c < 'A' || c > 'Z'); - data checksum = create_checksum(hrp, values, encoding); - data combined = cat(values, checksum); - std::string ret = hrp + '1'; - ret.reserve(ret.size() + combined.size()); - for (const auto c : combined) { - ret += CHARSET[c]; - } - return ret; -} - -/** Decode a Bech32 or Bech32m string. */ -DecodeResult decode(const std::string& str) { - bool lower = false, upper = false; - for (size_t i = 0; i < str.size(); ++i) { - unsigned char c = str[i]; - if (c >= 'a' && c <= 'z') lower = true; - else if (c >= 'A' && c <= 'Z') upper = true; - else if (c < 33 || c > 126) return {}; - } - if (lower && upper) return {}; - size_t pos = str.rfind('1'); - if (pos == str.npos || pos == 0 || pos + 7 > str.size()) { - 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]; - int8_t rev = CHARSET_REV[c]; - - if (rev == -1) { - return {}; - } - values[i] = rev; - } - std::string hrp; - for (size_t i = 0; i < pos; ++i) { - hrp += lc(str[i]); - } - Encoding result = verify_checksum(hrp, values); - if (result == Encoding::INVALID) return {}; - return {result, std::move(hrp), data(values.begin(), values.end() - 6)}; -} - -/** Convert from one power-of-2 number base to another. */ -bool convertbits(std::vector& out, const std::vector& in, int frombits, int tobits, bool pad) { - int acc = 0; - int bits = 0; - const int maxv = (1 << tobits) - 1; - const int max_acc = (1 << (frombits + tobits - 1)) - 1; - for (size_t i = 0; i < in.size(); ++i) { - int value = in[i]; - acc = ((acc << frombits) | value) & max_acc; - bits += frombits; - while (bits >= tobits) { - bits -= tobits; - out.push_back((acc >> bits) & maxv); - } - } - if (pad) { - if (bits) out.push_back((acc << (tobits - bits)) & maxv); - } else if (bits >= frombits || ((acc << (tobits - bits)) & maxv)) { - return false; - } - return true; -} - -} // namespace bech32 diff --git a/src/libspats/bech32.h b/src/libspats/bech32.h deleted file mode 100644 index 33dc430b59..0000000000 --- a/src/libspats/bech32.h +++ /dev/null @@ -1,63 +0,0 @@ -/* Copyright (c) 2017, 2021 Pieter Wuille - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -#ifndef BECH32_H_ -#define BECH32_H_ 1 - -#include -#include -#include - -#include - -namespace bech32 -{ - -enum class Encoding { - INVALID, - - BECH32, //! Bech32 encoding as defined in BIP173 - BECH32M, //! Bech32m encoding as defined in BIP350 -}; - -/** Encode a Bech32 or Bech32m string. If hrp contains uppercase characters, this will cause an - * assertion error. Encoding must be one of BECH32 or BECH32M. */ -std::string encode(const std::string& hrp, const std::vector& values, Encoding encoding); - -/** A type for the result of decoding. */ -struct DecodeResult -{ - Encoding encoding; //!< What encoding was detected in the result; Encoding::INVALID if failed. - std::string hrp; //!< The human readable part - std::vector data; //!< The payload (excluding checksum) - - DecodeResult() : encoding(Encoding::INVALID) {} - DecodeResult(Encoding enc, std::string&& h, std::vector&& d) : encoding(enc), hrp(std::move(h)), data(std::move(d)) {} -}; - -/** Decode a Bech32 or Bech32m string. */ -DecodeResult decode(const std::string& str); - -/** Convert from one power-of-2 number base to another. */ -bool convertbits(std::vector& out, const std::vector& in, int frombits, int tobits, bool pad); -} // namespace bech32 - -#endif // BECH32_H_ diff --git a/src/libspats/bpplus.cpp b/src/libspats/bpplus.cpp index c41a979dee..78b04e3bcc 100644 --- a/src/libspats/bpplus.cpp +++ b/src/libspats/bpplus.cpp @@ -1,5 +1,6 @@ #include "bpplus.h" -#include "transcript.h" +#include "../libspark/transcript.h" +#include "util.h" namespace spats { @@ -77,7 +78,7 @@ void BPPlus::prove( // Set up transcript, using the unpadded values // This is fine since the verifier canonically generates the same transcript - Transcript transcript(LABEL_TRANSCRIPT_BPPLUS); + spark::Transcript transcript(LABEL_TRANSCRIPT_BPPLUS); transcript.add("G", G); transcript.add("H", H); transcript.add("E", E); @@ -196,30 +197,21 @@ void BPPlus::prove( // Compute aL1, aR1 std::vector aL1, aR1; + aL1.reserve(N * M); + aR1.reserve(N * M); for (std::size_t i = 0; i < N * M; i++) { aL1.emplace_back(aL[i] - z); aR1.emplace_back(aR[i] + d[i] * y_powers[N * M - i] + z); } - // Compute alpha1 + // Compute alpha1, alpha2, alpha3 Scalar alpha1 = alpha; - Scalar z_even_powers = 1; - for (std::size_t j = 0; j < M; j++) { - z_even_powers *= z_square; - alpha1 += z_even_powers * r[j] * y_powers[N * M + 1]; - } - // Compute alpha2, alpha3 Scalar alpha2 = alpha_2; Scalar alpha3 = alpha_3; - z_even_powers = 1; - // asset_type_ = asset_type; - // identifier_ = identifier; + Scalar z_even_powers = 1; for (std::size_t j = 0; j < M; j++) { z_even_powers *= z_square; - // if (j >= unpadded_M) { - // asset_type_ = Scalar(uint64_t(0)); - // identifier_ = Scalar(uint64_t(0)); - // } + alpha1 += z_even_powers * r[j] * y_powers[N * M + 1]; alpha2 += z_even_powers * a[j] * y_powers[N * M + 1]; alpha3 += z_even_powers * iota[j] * y_powers[N * M + 1]; } @@ -369,6 +361,8 @@ bool BPPlus::verify(const std::vector >& unpadded_C, c std::size_t N_proofs = proofs.size(); std::size_t max_M = 0; // maximum number of padded aggregated values across all proofs + std::size_t final_size = 0; // size of each vector used in final multiscalar multiplication + // Check aggregated input consistency for (std::size_t k = 0; k < N_proofs; k++) { std::size_t unpadded_M = unpadded_C[k].size(); @@ -395,8 +389,14 @@ bool BPPlus::verify(const std::vector >& unpadded_C, c if (log2(N * M) != rounds) { return false; } + + // Update the final vector size: B, A1, A, (C_j), (L), (R) + final_size += 3 + M + 2 * rounds; } + // Update the final vector size: G, H, (Gi), (Hi) + final_size += 4 + 2 * max_M * N; + // Check the bounds on the batch if (max_M * N > Gi.size() || max_M * N > Hi.size()) { return false; @@ -405,6 +405,8 @@ bool BPPlus::verify(const std::vector >& unpadded_C, c // Set up final multiscalar multiplication and common scalars std::vector points; std::vector scalars; + points.reserve(final_size); + scalars.reserve(final_size); Scalar G_scalar, H_scalar; Scalar E_scalar, F_scalar; @@ -416,6 +418,19 @@ bool BPPlus::verify(const std::vector >& unpadded_C, c scalars.emplace_back(ZERO); } + std::vector> serialized_Gi; + serialized_Gi.resize(Gi.size()); + std::vector> serialized_Hi; + serialized_Hi.resize(Hi.size()); + // Serialize and cash Gi and Hi vectors + for (std::size_t i = 0; i < Gi.size(); i++) { + serialized_Gi[i].resize(GroupElement::serialize_size); + Gi[i].serialize(serialized_Gi[i].data()); + serialized_Hi[i].resize(GroupElement::serialize_size); + Hi[i].serialize(serialized_Hi[i].data()); + } + + // Process each proof and add to the batch for (std::size_t k_proofs = 0; k_proofs < N_proofs; k_proofs++) { const BPPlusProof proof = proofs[k_proofs]; @@ -429,13 +444,13 @@ bool BPPlus::verify(const std::vector >& unpadded_C, c } // Set up transcript - Transcript transcript(LABEL_TRANSCRIPT_BPPLUS); + spark::Transcript transcript(LABEL_TRANSCRIPT_BPPLUS); transcript.add("G", G); transcript.add("H", H); transcript.add("E", E); transcript.add("F", F); - transcript.add("Gi", Gi); - transcript.add("Hi", Hi); + transcript.add("Gi", serialized_Gi); + transcript.add("Hi", serialized_Hi); transcript.add("N", Scalar(N)); transcript.add("C", unpadded_C[k_proofs]); transcript.add("A", proof.A); diff --git a/src/libspats/bpplus_proof.h b/src/libspats/bpplus_proof.h index 9e690f9e42..fb5a75c72e 100644 --- a/src/libspats/bpplus_proof.h +++ b/src/libspats/bpplus_proof.h @@ -1,7 +1,7 @@ #ifndef FIRO_LIBSPATS_BPPLUS_PROOF_H #define FIRO_LIBSPATS_BPPLUS_PROOF_H -#include "params.h" +#include "../libspark/params.h" namespace spats { diff --git a/src/libspats/chaum.cpp b/src/libspats/chaum.cpp deleted file mode 100644 index 58128800f6..0000000000 --- a/src/libspats/chaum.cpp +++ /dev/null @@ -1,176 +0,0 @@ -#include "chaum.h" -#include "transcript.h" - -namespace spats { - -Chaum::Chaum(const GroupElement& F_, const GroupElement& G_, const GroupElement& H_, const GroupElement& U_): - F(F_), G(G_), H(H_), U(U_) { -} - -Scalar Chaum::challenge( - const Scalar& mu, - const std::vector& S, - const std::vector& T, - const GroupElement& A1, - const std::vector& A2 -) { - Transcript transcript(LABEL_TRANSCRIPT_CHAUM); - transcript.add("F", F); - transcript.add("G", G); - transcript.add("H", H); - transcript.add("U", U); - transcript.add("mu", mu); - transcript.add("S", S); - transcript.add("T", T); - transcript.add("A1", A1); - transcript.add("A2", A2); - - return transcript.challenge("c"); -} - -void Chaum::prove( - const Scalar& mu, - const std::vector& x, - const std::vector& y, - const std::vector& z, - const std::vector& S, - const std::vector& T, - ChaumProof& proof -) { - // Check statement validity - std::size_t n = x.size(); - if (!(y.size() == n && z.size() == n && S.size() == n && T.size() == n)) { - throw std::invalid_argument("Bad Chaum statement!"); - } - for (std::size_t i = 0; i < n; i++) { - if (!(F*x[i] + G*y[i] + H*z[i] == S[i] && T[i]*x[i] + G*y[i] == U)) { - throw std::invalid_argument("Bad Chaum statement!"); - } - } - - std::vector r; - r.resize(n); - std::vector s; - s.resize(n); - for (std::size_t i = 0; i < n; i++) { - r[i].randomize(); - s[i].randomize(); - } - Scalar t; - t.randomize(); - - proof.A1 = H*t; - proof.A2.resize(n); - for (std::size_t i = 0; i < n; i++) { - proof.A1 += F*r[i] + G*s[i]; - proof.A2[i] = T[i]*r[i] + G*s[i]; - } - - Scalar c = challenge(mu, S, T, proof.A1, proof.A2); - - proof.t1.resize(n); - proof.t3 = t; - Scalar c_power(c); - for (std::size_t i = 0; i < n; i++) { - if (c_power.isZero()) { - throw std::invalid_argument("Unexpected challenge!"); - } - proof.t1[i] = r[i] + c_power*x[i]; - proof.t2 += s[i] + c_power*y[i]; - proof.t3 += c_power*z[i]; - c_power *= c; - } -} - -bool Chaum::verify( - const Scalar& mu, - const std::vector& S, - const std::vector& T, - ChaumProof& proof -) { - // Check proof semantics - std::size_t n = S.size(); - if (!(T.size() == n && proof.A2.size() == n && proof.t1.size() == n)) { - throw std::invalid_argument("Bad Chaum semantics!"); - } - - Scalar c = challenge(mu, S, T, proof.A1, proof.A2); - if (c.isZero()) { - throw std::invalid_argument("Unexpected challenge!"); - } - std::vector c_powers; - c_powers.emplace_back(c); - for (std::size_t i = 1; i < n; i++) { - c_powers.emplace_back(c_powers[i-1]*c); - if (c_powers[i].isZero()) { - throw std::invalid_argument("Unexpected challenge!"); - } - } - - // Weight the verification equations - Scalar w; - while (w.isZero()) { - w.randomize(); - } - - std::vector scalars; - std::vector points; - scalars.reserve(3*n + 5); - points.reserve(3*n + 5); - - // F - Scalar F_scalar; - for (std::size_t i = 0; i < n; i++) { - F_scalar -= proof.t1[i]; - } - scalars.emplace_back(F_scalar); - points.emplace_back(F); - - // G - scalars.emplace_back(proof.t2.negate() - w*proof.t2); - points.emplace_back(G); - - // H - scalars.emplace_back(proof.t3.negate()); - points.emplace_back(H); - - // U - Scalar U_scalar; - for (std::size_t i = 0; i < n; i++) { - U_scalar += c_powers[i]; - } - U_scalar *= w; - scalars.emplace_back(U_scalar); - points.emplace_back(U); - - // A1 - scalars.emplace_back(Scalar((uint64_t) 1)); - points.emplace_back(proof.A1); - - // {A2} - GroupElement A2_sum = proof.A2[0]; - for (std::size_t i = 1; i < n; i++) { - A2_sum += proof.A2[i]; - } - scalars.emplace_back(w); - points.emplace_back(A2_sum); - - // {S} - for (std::size_t i = 0; i < n; i++) { - scalars.emplace_back(c_powers[i]); - points.emplace_back(S[i]); - } - - // {T} - for (std::size_t i = 0; i < n; i++) { - scalars.emplace_back(w.negate()*proof.t1[i]); - points.emplace_back(T[i]); - } - - secp_primitives::MultiExponent multiexp(points, scalars); - // merged equalities and doing check in one multiexponentation, - // for weighting we use random w - return multiexp.get_multiple().isInfinity(); -} - -} diff --git a/src/libspats/chaum.h b/src/libspats/chaum.h deleted file mode 100644 index f696cc53db..0000000000 --- a/src/libspats/chaum.h +++ /dev/null @@ -1,45 +0,0 @@ -#ifndef FIRO_LIBSPATS_CHAUM_H -#define FIRO_LIBSPATS_CHAUM_H - -#include "chaum_proof.h" -#include - -namespace spats { - -class Chaum { -public: - Chaum(const GroupElement& F, const GroupElement& G, const GroupElement& H, const GroupElement& U); - - void prove( - const Scalar& mu, - const std::vector& x, - const std::vector& y, - const std::vector& z, - const std::vector& S, - const std::vector& T, - ChaumProof& proof - ); - bool verify( - const Scalar& mu, - const std::vector& S, - const std::vector& T, - ChaumProof& proof - ); - -private: - Scalar challenge( - const Scalar& mu, - const std::vector& S, - const std::vector& T, - const GroupElement& A1, - const std::vector& A2 - ); - const GroupElement& F; - const GroupElement& G; - const GroupElement& H; - const GroupElement& U; -}; - -} - -#endif diff --git a/src/libspats/chaum_proof.h b/src/libspats/chaum_proof.h deleted file mode 100644 index 2c17f18f9e..0000000000 --- a/src/libspats/chaum_proof.h +++ /dev/null @@ -1,32 +0,0 @@ -#ifndef FIRO_LIBSPATS_CHAUM_PROOF_H -#define FIRO_LIBSPATS_CHAUM_PROOF_H - -#include "params.h" - -namespace spats { - -class ChaumProof{ -public: - inline std::size_t memoryRequired() const { - return GroupElement::memoryRequired() + A2.size()*GroupElement::memoryRequired() + t1.size()*Scalar::memoryRequired() + 2*Scalar::memoryRequired(); - } - - ADD_SERIALIZE_METHODS; - template - inline void SerializationOp(Stream& s, Operation ser_action) { - READWRITE(A1); - READWRITE(A2); - READWRITE(t1); - READWRITE(t2); - READWRITE(t3); - } - -public: - GroupElement A1; - std::vector A2; - std::vector t1; - Scalar t2, t3; -}; -} - -#endif diff --git a/src/libspats/coin.cpp b/src/libspats/coin.cpp index fa148f6f76..d0ae286ba1 100644 --- a/src/libspats/coin.cpp +++ b/src/libspats/coin.cpp @@ -8,18 +8,18 @@ using namespace secp_primitives; Coin::Coin() {} -Coin::Coin(const Params* params) +Coin::Coin(const spark::Params* params) { this->params = params; } Coin::Coin( - const Params* params, + const spark::Params* params, const char type, const Scalar& k, const Scalar& a, const Scalar& iota, - const Address& address, + const spark::Address& address, const uint64_t& v, const std::string& memo, const std::vector& serial_context) @@ -41,13 +41,13 @@ Coin::Coin( // // Construct the recovery key - this->K = SpatsUtils::hash_div(address.get_d()) * SpatsUtils::hash_k(k); + this->K = spark::SparkUtils::hash_div(address.get_d()) * spark::SparkUtils::hash_k(k); // Construct the serial commitment - this->S = this->params->get_F() * SpatsUtils::hash_ser(k, serial_context) + address.get_Q2(); + this->S = this->params->get_F() * spark::SparkUtils::hash_ser(k, serial_context) + address.get_Q2(); // // Construct the value commitment - this->C = this->params->get_E() * a + this->params->get_F() * iota + this->params->get_G() * Scalar(v) + this->params->get_H() * SpatsUtils::hash_val(k); + this->C = this->params->get_E() * a + this->params->get_F() * iota + this->params->get_G() * Scalar(v) + this->params->get_H() * spark::SparkUtils::hash_val(k); // Check the memo validity, and pad if needed if (memo.size() > this->params->get_memo_bytes()) { @@ -57,6 +57,9 @@ Coin::Coin( std::vector padded_memo(memo_bytes); padded_memo.resize(this->params->get_memo_bytes()); + // Prepend the unpadded memo length + padded_memo.insert(padded_memo.begin(), (unsigned char) memo.size()); + // // Type-specific elements // @@ -68,10 +71,10 @@ Coin::Coin( MintCoinRecipientData r; r.d = address.get_d(); r.k = k; - r.memo = std::string(padded_memo.begin(), padded_memo.end()); + r.padded_memo = std::string(padded_memo.begin(), padded_memo.end()); CDataStream r_stream(SER_NETWORK, PROTOCOL_VERSION); r_stream << r; - this->r_ = AEAD::encrypt(address.get_Q1() * SpatsUtils::hash_k(k), "Mint coin data", r_stream); + this->r_ = spark::AEAD::encrypt(address.get_Q1() * spark::SparkUtils::hash_k(k), "Mint coin data", r_stream); } else { // Encrypt recipient data SpendCoinRecipientData r; @@ -80,33 +83,33 @@ Coin::Coin( r.v = v; r.d = address.get_d(); r.k = k; - r.memo = std::string(padded_memo.begin(), padded_memo.end()); + r.padded_memo = std::string(padded_memo.begin(), padded_memo.end()); CDataStream r_stream(SER_NETWORK, PROTOCOL_VERSION); r_stream << r; - this->r_ = AEAD::encrypt(address.get_Q1() * SpatsUtils::hash_k(k), "Spend coin data", r_stream); + this->r_ = spark::AEAD::encrypt(address.get_Q1() * spark::SparkUtils::hash_k(k), "Spend coin data", r_stream); } } // Validate a coin for identification // NOTE: This assumes the coin has a valid associated range proof, which MUST be separately checked as part of the valid transaction that produced it bool Coin::validate( - const IncomingViewKey& incoming_view_key, + const spark::IncomingViewKey& incoming_view_key, IdentifiedCoinData& data) { // Check recovery key - if (SpatsUtils::hash_div(data.d) * SpatsUtils::hash_k(data.k) != this->K) { + if (spark::SparkUtils::hash_div(data.d) * spark::SparkUtils::hash_k(data.k) != this->K) { return false; } // Check value commitment - if (this->params->get_E() * data.a + this->params->get_F() * data.iota + this->params->get_G() * Scalar(data.v) + this->params->get_H() * SpatsUtils::hash_val(data.k) != this->C) { + if (this->params->get_E() * data.a + this->params->get_F() * data.iota + this->params->get_G() * Scalar(data.v) + this->params->get_H() * spark::SparkUtils::hash_val(data.k) != this->C) { return false; } // Check serial commitment data.i = incoming_view_key.get_diversifier(data.d); - if (this->params->get_F() * (SpatsUtils::hash_ser(data.k, this->serial_context) + SpatsUtils::hash_Q2(incoming_view_key.get_s1(), data.i)) + incoming_view_key.get_P2() != this->S) { + if (this->params->get_F() * (spark::SparkUtils::hash_ser(data.k, this->serial_context) + spark::SparkUtils::hash_Q2(incoming_view_key.get_s1(), data.i)) + incoming_view_key.get_P2() != this->S) { return false; } @@ -114,17 +117,17 @@ bool Coin::validate( } // Recover a coin -RecoveredCoinData Coin::recover(const FullViewKey& full_view_key, const IdentifiedCoinData& data) +RecoveredCoinData Coin::recover(const spark::FullViewKey& full_view_key, const IdentifiedCoinData& data) { RecoveredCoinData recovered_data; - recovered_data.s = SpatsUtils::hash_ser(data.k, this->serial_context) + SpatsUtils::hash_Q2(full_view_key.get_s1(), data.i) + full_view_key.get_s2(); + recovered_data.s = spark::SparkUtils::hash_ser(data.k, this->serial_context) + spark::SparkUtils::hash_Q2(full_view_key.get_s1(), data.i) + full_view_key.get_s2(); recovered_data.T = (this->params->get_U() + full_view_key.get_D().inverse()) * recovered_data.s.inverse(); return recovered_data; } // Identify a coin -IdentifiedCoinData Coin::identify(const IncomingViewKey& incoming_view_key) +IdentifiedCoinData Coin::identify(const spark::IncomingViewKey& incoming_view_key) { IdentifiedCoinData data; @@ -134,35 +137,50 @@ IdentifiedCoinData Coin::identify(const IncomingViewKey& incoming_view_key) try { // Decrypt recipient data - CDataStream stream = AEAD::decrypt_and_verify(this->K * incoming_view_key.get_s1(), "Mint coin data", this->r_); + CDataStream stream = spark::AEAD::decrypt_and_verify(this->K * incoming_view_key.get_s1(), "Mint coin data", this->r_); stream >> r; } catch (...) { + std::cout<<"failed1"< this->params->get_memo_bytes()) { + throw std::runtime_error("Unable to identify coin"); + } + data.d = r.d; data.a = this->a; data.iota = this->iota; data.v = this->v; data.k = r.k; - data.memo = r.memo; + data.memo = std::string(r.padded_memo.begin() + 1, r.padded_memo.begin() + 1 + memo_length); // remove the encoded length and padding } else { SpendCoinRecipientData r; try { // Decrypt recipient data - CDataStream stream = AEAD::decrypt_and_verify(this->K * incoming_view_key.get_s1(), "Spend coin data", this->r_); + CDataStream stream = spark::AEAD::decrypt_and_verify(this->K * incoming_view_key.get_s1(), "Spend coin data", this->r_); stream >> r; } catch (...) { + std::cout<<"failed2"< this->params->get_memo_bytes()) { + throw std::runtime_error("Unable to identify coin"); + } + data.a = r.a; data.iota = r.iota; data.d = r.d; data.v = r.v; data.k = r.k; - data.memo = r.memo; + data.memo = std::string(r.padded_memo.begin() + 1, r.padded_memo.begin() + 1 + memo_length); // remove the encoded length and padding } // Validate the coin @@ -176,7 +194,7 @@ IdentifiedCoinData Coin::identify(const IncomingViewKey& incoming_view_key) std::size_t Coin::memoryRequired() { secp_primitives::GroupElement groupElement; - return 1 + groupElement.memoryRequired() * 3 + 32 + AEAD_TAG_SIZE; + return 1 + groupElement.memoryRequired() * 3 + 32 + spark::AEAD_TAG_SIZE; } bool Coin::operator==(const Coin& other) const @@ -220,7 +238,7 @@ void Coin::setSerialContext(const std::vector& serial_context_) serial_context = serial_context_; } -void Coin::setParams(const Params* params) +void Coin::setParams(const spark::Params* params) { this->params = params; } diff --git a/src/libspats/coin.h b/src/libspats/coin.h index ca7e2281c9..96305d42a7 100644 --- a/src/libspats/coin.h +++ b/src/libspats/coin.h @@ -1,10 +1,10 @@ #ifndef FIRO_SPATS_COIN_H #define FIRO_SPATS_COIN_H #include "../uint256.h" -#include "aead.h" +#include "../libspark/aead.h" #include "bpplus.h" -#include "keys.h" -#include "params.h" +#include "../libspark/keys.h" +#include "../libspark/params.h" #include "util.h" #include @@ -36,7 +36,7 @@ struct RecoveredCoinData { struct MintCoinRecipientData { std::vector d; // encrypted diversifier Scalar k; // nonce - std::string memo; // memo + std::string padded_memo; // padded memo with prepended one-byte length ADD_SERIALIZE_METHODS; @@ -45,7 +45,7 @@ struct MintCoinRecipientData { { READWRITE(d); READWRITE(k); - READWRITE(memo); + READWRITE(padded_memo); } }; @@ -56,7 +56,7 @@ struct SpendCoinRecipientData { Scalar k; // nonce Scalar a; // asset type Scalar iota; // identifier - std::string memo; // memo + std::string padded_memo; // padded memo with prepended one-byte length ADD_SERIALIZE_METHODS; @@ -68,7 +68,7 @@ struct SpendCoinRecipientData { READWRITE(v); READWRITE(d); READWRITE(k); - READWRITE(memo); + READWRITE(padded_memo); } }; @@ -76,23 +76,23 @@ class Coin { public: Coin(); - Coin(const Params* params); + Coin(const spark::Params* params); Coin( - const Params* params, + const spark::Params* params, const char type, const Scalar& k, const Scalar& a, const Scalar& iota, - const Address& address, + const spark::Address& address, const uint64_t& v, const std::string& memo, const std::vector& serial_context); // Given an incoming view key, extract the coin's nonce, diversifier, value, and memo - IdentifiedCoinData identify(const IncomingViewKey& incoming_view_key); + IdentifiedCoinData identify(const spark::IncomingViewKey& incoming_view_key); // Given a full view key, extract the coin's serial number and tag - RecoveredCoinData recover(const FullViewKey& full_view_key, const IdentifiedCoinData& data); + RecoveredCoinData recover(const spark::FullViewKey& full_view_key, const IdentifiedCoinData& data); static std::size_t memoryRequired(); @@ -102,17 +102,17 @@ class Coin // type and v are not included in hash uint256 getHash() const; - void setParams(const Params* params); + void setParams(const spark::Params* params); void setSerialContext(const std::vector& serial_context_); protected: - bool validate(const IncomingViewKey& incoming_view_key, IdentifiedCoinData& data); + bool validate(const spark::IncomingViewKey& incoming_view_key, IdentifiedCoinData& data); public: - const Params* params; + const spark::Params* params; char type; // type flag GroupElement S, K, C; // serial commitment, recovery key, value commitment - AEADEncryptedData r_; // encrypted recipient data + spark::AEADEncryptedData r_; // encrypted recipient data uint64_t v; // value Scalar a, iota; // asset type, identifier std::vector serial_context; // context to which the serial commitment should be bound (not serialized, but inferred) diff --git a/src/libspats/f4grumble.cpp b/src/libspats/f4grumble.cpp deleted file mode 100644 index f1a4228fbe..0000000000 --- a/src/libspats/f4grumble.cpp +++ /dev/null @@ -1,152 +0,0 @@ -// A design for address scrambling based on `f4jumble`: https://zips.z.cash/zip-0316#jumbling -// This design differs from `f4jumble` to account for limitations on SHA512 -// These limitations are unfortunate, but such is life sometimes -// -// To account for these limitations, we do the following: -// - Place extra restrictions on length to avoid XOF input encoding (and because we don't need it) -// - Replace personalization with fixed-length inputs; note that length is NOT prepended -// - Truncate outputs to the proper length -// -// Additionally, we account for the number of rounds by limiting the round counter encoding - -#include "f4grumble.h" - -namespace spats { - -using namespace secp_primitives; - -// Compute the XOR of two byte vectors -std::vector F4Grumble::vec_xor(const std::vector& x, const std::vector& y) { - if (x.size() != y.size()) { - throw std::invalid_argument("Mismatched vector sizes"); - } - - std::vector result; - result.reserve(x.size()); - for (std::size_t i = 0; i < x.size(); i++) { - result.emplace_back(x[i] ^ y[i]); - } - - return result; -} - -// Return the maximum allowed input size in bytes -std::size_t F4Grumble::get_max_size() { - return 2 * EVP_MD_size(EVP_sha512()); -} - -// Instantiate with a given network identifier and expected input length -F4Grumble::F4Grumble(const unsigned char network, const int l_M) { - // Assert the length is valid - if (l_M > 2 * EVP_MD_size(EVP_sha512())) { - throw std::invalid_argument("Bad address size"); - } - - this->network = network; - this->l_M = l_M; - this->l_L = l_M / 2; - this->l_R = l_M - l_L; -} - -// Encode the input data -std::vector F4Grumble::encode(const std::vector& input) { - // Check the input size - if (input.size() != l_M) { - throw std::invalid_argument("Bad address size"); - } - - // Split the input - std::vector a = std::vector(input.begin(), input.begin() + this->l_M / 2); - std::vector b = std::vector(input.begin() + this->l_M / 2, input.end()); - - // Perform the Feistel operations - std::vector x = vec_xor(b, G(0, a)); - std::vector y = vec_xor(a, H(0, x)); - std::vector d = vec_xor(x, G(1, y)); - std::vector c = vec_xor(y, H(1, d)); - - // Return the concatenation - std::vector result(c); - result.insert(result.end(), d.begin(), d.end()); - return result; -} - -// Decode the input data -std::vector F4Grumble::decode(const std::vector& input) { - // Check the input size - if (input.size() != l_M) { - throw std::invalid_argument("Bad address size"); - } - - // Split the input - std::vector c = std::vector(input.begin(), input.begin() + this->l_M / 2); - std::vector d = std::vector(input.begin() + this->l_M / 2, input.end()); - - // Perform the Feistel operations - std::vector y = vec_xor(c, H(1, d)); - std::vector x = vec_xor(d, G(1, y)); - std::vector a = vec_xor(y, H(0, x)); - std::vector b = vec_xor(x, G(0, a)); - - // Return the concatenation - std::vector result(a); - result.insert(result.end(), b.begin(), b.end()); - return result; -} - -// Feistel round functions -std::vector F4Grumble::G(const unsigned char i, const std::vector& u) { - EVP_MD_CTX* ctx = EVP_MD_CTX_new(); - EVP_DigestInit_ex(ctx, EVP_sha512(), NULL); - - // Bind the domain separator and network - std::vector domain(LABEL_F4GRUMBLE_G.begin(), LABEL_F4GRUMBLE_G.end()); - EVP_DigestUpdate(ctx, domain.data(), domain.size()); - EVP_DigestUpdate(ctx, &this->network, sizeof(this->network)); - - // Include the round index - EVP_DigestUpdate(ctx, &i, sizeof(i)); - - // Include the input data - EVP_DigestUpdate(ctx, u.data(), u.size()); - - // Finalize the hash and resize - std::vector result; - result.resize(EVP_MD_size(EVP_sha512())); - - unsigned int TEMP; - EVP_DigestFinal_ex(ctx, result.data(), &TEMP); - EVP_MD_CTX_free(ctx); - result.resize(this->l_R); - - return result; -} - -std::vector F4Grumble::H(const unsigned char i, const std::vector& u) { - EVP_MD_CTX* ctx = EVP_MD_CTX_new(); - EVP_DigestInit_ex(ctx, EVP_sha512(), NULL); - - // Bind the domain separator and network - std::vector domain(LABEL_F4GRUMBLE_H.begin(), LABEL_F4GRUMBLE_H.end()); - EVP_DigestUpdate(ctx, domain.data(), domain.size()); - EVP_DigestUpdate(ctx, &this->network, sizeof(this->network)); - - // Include the round index - EVP_DigestUpdate(ctx, &i, sizeof(i)); - - // Include the input data - EVP_DigestUpdate(ctx, u.data(), u.size()); - - // Finalize the hash and resize - std::vector result; - result.resize(EVP_MD_size(EVP_sha512())); - - unsigned int TEMP; - EVP_DigestFinal_ex(ctx, result.data(), &TEMP); - EVP_MD_CTX_free(ctx); - result.resize(this->l_L); - - return result; -} - -} diff --git a/src/libspats/f4grumble.h b/src/libspats/f4grumble.h deleted file mode 100644 index 4ebf77bf62..0000000000 --- a/src/libspats/f4grumble.h +++ /dev/null @@ -1,32 +0,0 @@ -#ifndef FIRO_SPATS_F4GRUMBLE_H -#define FIRO_SPATS_F4GRUMBLE_H -#include -#include "util.h" - -namespace spats { - -using namespace secp_primitives; - -class F4Grumble { -public: - F4Grumble(const unsigned char network, const int l_M); - - std::vector encode(const std::vector& input); - std::vector decode(const std::vector& input); - - static std::size_t get_max_size(); - -private: - static std::vector vec_xor(const std::vector& x, const std::vector& y); - - // The internal Feistel round functions - std::vector G(const unsigned char i, const std::vector& u); - std::vector H(const unsigned char i, const std::vector& u); - - unsigned char network; - int l_M, l_L, l_R; -}; - -} - -#endif diff --git a/src/libspats/grootle.cpp b/src/libspats/grootle.cpp deleted file mode 100644 index ef55fa6afd..0000000000 --- a/src/libspats/grootle.cpp +++ /dev/null @@ -1,573 +0,0 @@ -#include "grootle.h" -#include "transcript.h" - -namespace spats { - -// Useful scalar constants -const Scalar ZERO = Scalar(uint64_t(0)); -const Scalar ONE = Scalar(uint64_t(1)); -const Scalar TWO = Scalar(uint64_t(2)); - -Grootle::Grootle( - const GroupElement& H_, - const std::vector& Gi_, - const std::vector& Hi_, - const std::size_t n_, - const std::size_t m_) - : H (H_) - , Gi (Gi_) - , Hi (Hi_) - , n (n_) - , m (m_) -{ - if (!(n > 1 && m > 1)) { - throw std::invalid_argument("Bad Grootle size parameters!"); - } - if (Gi.size() != n*m || Hi.size() != n*m) { - throw std::invalid_argument("Bad Grootle generator size!"); - } -} - -// Compute a delta function vector -static inline std::vector convert_to_sigma(std::size_t num, const std::size_t n, const std::size_t m) { - std::vector result; - result.reserve(n*m); - - for (std::size_t j = 0; j < m; j++) { - for (std::size_t i = 0; i < n; i++) { - if (i == (num % n)) { - result.emplace_back(ONE); - } else { - result.emplace_back(ZERO); - } - } - num /= n; - } - - return result; -} - -// Decompose an integer with arbitrary base and padded size -static inline std::vector decompose(std::size_t num, const std::size_t n, const std::size_t m) { - std::vector result; - result.reserve(m); - - while (num != 0) { - result.emplace_back(num % n); - num /= n; - } - result.resize(m); - - return result; -} - -// Compute a double Pedersen vector commitment -static inline GroupElement vector_commit(const std::vector& Gi, const std::vector& Hi, const std::vector& a, const std::vector& b, const GroupElement& H, const Scalar& r) { - if (Gi.size() != a.size() || Hi.size() != b.size()) { - throw std::runtime_error("Vector commitment size mismatch!"); - } - return secp_primitives::MultiExponent(Gi, a).get_multiple() + secp_primitives::MultiExponent(Hi, b).get_multiple() + H*r; -} - -// Compute a convolution with a degree-one polynomial -static inline void convolve(const Scalar& x_1, const Scalar& x_0, std::vector& coefficients) { - if (coefficients.empty()) { - throw std::runtime_error("Empty convolution coefficient vector!"); - } - - std::size_t degree = coefficients.size() - 1; - coefficients.emplace_back(x_1*coefficients[degree]); - for (std::size_t i = degree; i >=1; i--) { - coefficients[i] = x_0*coefficients[i] + x_1*coefficients[i-1]; - } - coefficients[0] *= x_0; -} - -static bool compute_fs( - const GrootleProof& proof, - const Scalar& x, - std::vector& f_, - const std::size_t n, - const std::size_t m) { - for (std::size_t j = 0; j < proof.f.size(); ++j) { - if(proof.f[j] == x) - return false; - } - - f_.reserve(n * m); - for (std::size_t j = 0; j < m; ++j) - { - f_.push_back(Scalar(uint64_t(0))); - Scalar temp; - std::size_t k = n - 1; - for (std::size_t i = 0; i < k; ++i) - { - temp += proof.f[j * k + i]; - f_.emplace_back(proof.f[j * k + i]); - } - f_[j * n] = x - temp; - } - return true; -} - -static void compute_batch_fis( - Scalar& f_sum, - const Scalar& f_i, - int j, - const std::vector& f, - const Scalar& y, - std::vector::iterator& ptr, - std::vector::iterator start_ptr, - std::vector::iterator end_ptr, - const std::size_t n) { - j--; - if (j == -1) - { - if(ptr >= start_ptr && ptr < end_ptr){ - *ptr++ += f_i * y; - f_sum += f_i; - } - return; - } - - Scalar t; - - for (std::size_t i = 0; i < n; i++) - { - t = f[j * n + i]; - t *= f_i; - - compute_batch_fis(f_sum, t, j, f, y, ptr, start_ptr, end_ptr, n); - } -} - -void Grootle::prove( - const std::size_t l, - const Scalar& s, - const std::vector& S, - const GroupElement& S1, - const Scalar& v, - const std::vector& V, - const GroupElement& V1, - const std::vector& root, - GrootleProof& proof) { - // Check statement validity - std::size_t N = (std::size_t) pow(n, m); // padded input size - std::size_t size = S.size(); // actual input size - if (l >= size) { - throw std::invalid_argument("Bad Grootle secret index!"); - } - if (V.size() != S.size()) { - throw std::invalid_argument("Bad Grootle input vector sizes!"); - } - if (size > N || size == 0) { - throw std::invalid_argument("Bad Grootle size parameter!"); - } - if (S[l] + S1.inverse() != H*s) { - throw std::invalid_argument("Bad Grootle proof statement!"); - } - if (V[l] + V1.inverse() != H*v) { - throw std::invalid_argument("Bad Grootle proof statement!"); - } - - // Set up transcript - Transcript transcript(LABEL_TRANSCRIPT_GROOTLE); - transcript.add("H", H); - transcript.add("Gi", Gi); - transcript.add("Hi", Hi); - transcript.add("n", Scalar(n)); - transcript.add("m", Scalar(m)); - transcript.add("root", root); - transcript.add("S1", S1); - transcript.add("V1", V1); - - // Compute A - std::vector a; - a.resize(n*m); - for (std::size_t j = 0; j < m; j++) { - for (std::size_t i = 1; i < n; i++) { - a[j*n + i].randomize(); - a[j*n] -= a[j*n + i]; - } - } - std::vector d; - d.resize(n*m); - for (std::size_t i = 0; i < n*m; i++) { - d[i] = a[i].square().negate(); - } - Scalar rA; - rA.randomize(); - proof.A = vector_commit(Gi, Hi, a, d, H, rA); - - // Compute B - std::vector sigma = convert_to_sigma(l, n, m); - std::vector c; - c.resize(n*m); - for (std::size_t i = 0; i < n*m; i++) { - c[i] = a[i]*(ONE - TWO*sigma[i]); - } - Scalar rB; - rB.randomize(); - proof.B = vector_commit(Gi, Hi, sigma, c, H, rB); - - // Compute convolution terms - std::vector> P_i_j; - P_i_j.resize(size); - for (std::size_t i = 0; i < size - 1; ++i) - { - std::vector& coefficients = P_i_j[i]; - std::vector I = decompose(i, n, m); - coefficients.push_back(a[I[0]]); - coefficients.push_back(sigma[I[0]]); - for (std::size_t j = 1; j < m; ++j) { - convolve(sigma[j*n + I[j]], a[j*n + I[j]], coefficients); - } - } - - /* - * To optimize calculation of sum of all polynomials indices 's' = size-1 through 'n^m-1' we use the - * fact that sum of all of elements in each row of 'a' array is zero. Computation is done by going - * through n-ary representation of 's' and increasing "digit" at each position to 'n-1' one by one. - * During every step digits at higher positions are fixed and digits at lower positions go through all - * possible combinations with a total corresponding polynomial sum of 'x^j'. - * - * The math behind optimization (TeX notation): - * - * \sum_{i=s+1}^{N-1}p_i(x) = - * \sum_{j=0}^{m-1} - * \left[ - * \left( \sum_{i=s_j+1}^{n-1}(\delta_{l_j,i}x+a_{j,i}) \right) - * \left( \prod_{k=j}^{m-1}(\delta_{l_k,s_k}x+a_{k,s_k}) \right) - * x^j - * \right] - */ - - std::vector I = decompose(size - 1, n, m); - std::vector lj = decompose(l, n, m); - - std::vector p_i_sum; - p_i_sum.emplace_back(ONE); - std::vector> partial_p_s; - - // Pre-calculate product parts and calculate p_s(x) at the same time, put the latter into p_i_sum - for (std::ptrdiff_t j = m - 1; j >= 0; j--) { - partial_p_s.push_back(p_i_sum); - convolve(sigma[j*n + I[j]], a[j*n + I[j]], p_i_sum); - } - - for (std::size_t j = 0; j < m; j++) { - // \sum_{i=s_j+1}^{n-1}(\delta_{l_j,i}x+a_{j,i}) - Scalar a_sum(uint64_t(0)); - for (std::size_t i = I[j] + 1; i < n; i++) - a_sum += a[j * n + i]; - Scalar x_sum(uint64_t(lj[j] >= I[j]+1 ? 1 : 0)); - - // Multiply by \prod_{k=j}^{m-1}(\delta_{l_k,s_k}x+a_{k,s_k}) - std::vector &polynomial = partial_p_s[m - j - 1]; - convolve(x_sum, a_sum, polynomial); - - // Multiply by x^j and add to the result - for (std::size_t k = 0; k < m - j; k++) - p_i_sum[j + k] += polynomial[k]; - } - - P_i_j[size - 1] = p_i_sum; - - // Perform the commitment offsets - std::vector S_offset(S); - std::vector V_offset(V); - GroupElement S1_inverse = S1.inverse(); - GroupElement V1_inverse = V1.inverse(); - for (std::size_t k = 0; k < S_offset.size(); k++) { - S_offset[k] += S1_inverse; - V_offset[k] += V1_inverse; - } - - // Generate masks - std::vector rho_S, rho_V; - rho_S.resize(m); - rho_V.resize(m); - for (std::size_t j = 0; j < m; j++) { - rho_S[j].randomize(); - rho_V[j].randomize(); - } - - proof.X.reserve(m); - proof.X1.reserve(m); - for (std::size_t j = 0; j < m; ++j) - { - std::vector P_i; - P_i.reserve(size); - for (std::size_t i = 0; i < size; ++i){ - P_i.emplace_back(P_i_j[i][j]); - } - - // S - secp_primitives::MultiExponent mult_S(S_offset, P_i); - proof.X.emplace_back(mult_S.get_multiple() + H*rho_S[j]); - - // V - secp_primitives::MultiExponent mult_V(V_offset, P_i); - proof.X1.emplace_back(mult_V.get_multiple() + H*rho_V[j]); - } - - // Challenge - transcript.add("A", proof.A); - transcript.add("B", proof.B); - transcript.add("X", proof.X); - transcript.add("X1", proof.X1); - Scalar x = transcript.challenge("x"); - - // Compute f - proof.f.reserve(m*(n - 1)); - for (std::size_t j = 0; j < m; j++) - { - for (std::size_t i = 1; i < n; i++) { - proof.f.emplace_back(sigma[(j * n) + i] * x + a[(j * n) + i]); - } - } - - // Compute zA, zC - proof.z = rB * x + rA; - - // Compute zS, zV - proof.zS = s * x.exponent(uint64_t(m)); - proof.zV = v * x.exponent(uint64_t(m)); - Scalar sumS, sumV; - - Scalar x_powers(uint64_t(1)); - for (std::size_t j = 0; j < m; ++j) { - sumS += (rho_S[j] * x_powers); - sumV += (rho_V[j] * x_powers); - x_powers *= x; - } - proof.zS -= sumS; - proof.zV -= sumV; -} - -// Verify a single proof -bool Grootle::verify( - const std::vector& S, - const GroupElement& S1, - const std::vector& V, - const GroupElement& V1, - const std::vector& root, - const std::size_t size, - const GrootleProof& proof) { - std::vector S1_batch = {S1}; - std::vector V1_batch = {V1}; - std::vector size_batch = {size}; - std::vector> root_batch = {root}; - std::vector proof_batch = {proof}; - - return verify(S, S1_batch, V, V1_batch, root_batch, size_batch, proof_batch); -} - -// Verify a batch of proofs -bool Grootle::verify( - const std::vector& S, - const std::vector& S1, - const std::vector& V, - const std::vector& V1, - const std::vector>& roots, - const std::vector& sizes, - const std::vector& proofs) { - // Sanity checks - if (n < 2 || m < 2) { - LogPrintf("Verifier parameters are invalid"); - return false; - } - std::size_t M = proofs.size(); - std::size_t N = (std::size_t)pow(n, m); - - if (S.size() == 0) { - LogPrintf("Cannot have empty commitment set"); - return false; - } - if (S.size() > N) { - LogPrintf("Commitment set is too large"); - return false; - } - if (S.size() != V.size()) { - LogPrintf("Commitment set sizes do not match"); - return false; - } - if (S1.size() != M || V1.size() != M) { - LogPrintf("Invalid number of offsets provided"); - return false; - } - if (sizes.size() != M) { - LogPrintf("Invalid set size vector size"); - return false; - } - if (roots.size() != M) { - LogPrintf("Invalid root vector size"); - return false; - } - - // Check proof semantics - for (std::size_t t = 0; t < M; t++) { - GrootleProof proof = proofs[t]; - if (proof.X.size() != m || proof.X1.size() != m) { - LogPrintf("Bad proof vector size!"); - return false; - } - if (proof.f.size() != m*(n-1)) { - LogPrintf("Bad proof vector size!"); - return false; - } - } - - // Commitment binding weight; intentionally restricted range for efficiency, but must be nonzero - // NOTE: this may initialize with a PRNG, which should be sufficient for this use - std::random_device generator; - std::uniform_int_distribution distribution; - Scalar bind_weight(ZERO); - while (bind_weight == ZERO) { - bind_weight = Scalar(distribution(generator)); - } - - // Bind the commitment lists - std::vector commits; - commits.reserve(S.size()); - for (std::size_t i = 0; i < S.size(); i++) { - commits.emplace_back(S[i] + V[i]*bind_weight); - } - - // Final batch multiscalar multiplication - Scalar H_scalar; - std::vector Gi_scalars; - std::vector Hi_scalars; - std::vector commit_scalars; - Gi_scalars.resize(n*m); - Hi_scalars.resize(n*m); - commit_scalars.resize(commits.size()); - - // Set up the final batch elements - std::vector points; - std::vector scalars; - std::size_t final_size = 1 + 2*m*n + commits.size(); // F, (Gi), (Hi), (commits) - for (std::size_t t = 0; t < M; t++) { - final_size += 2 + proofs[t].X.size() + proofs[t].X1.size(); // A, B, (Gs), (Gv) - } - points.reserve(final_size); - scalars.reserve(final_size); - - // Index decomposition, which is common among all proofs - std::vector > I_; - I_.reserve(commits.size()); - I_.resize(commits.size()); - for (std::size_t i = 0; i < commits.size(); i++) { - I_[i] = decompose(i, n, m); - } - - // Process all proofs - for (std::size_t t = 0; t < M; t++) { - GrootleProof proof = proofs[t]; - - // Reconstruct the challenge - Transcript transcript(LABEL_TRANSCRIPT_GROOTLE); - transcript.add("H", H); - transcript.add("Gi", Gi); - transcript.add("Hi", Hi); - transcript.add("n", Scalar(n)); - transcript.add("m", Scalar(m)); - transcript.add("root", roots[t]); - transcript.add("S1", S1[t]); - transcript.add("V1", V1[t]); - transcript.add("A", proof.A); - transcript.add("B", proof.B); - transcript.add("X", proof.X); - transcript.add("X1", proof.X1); - Scalar x = transcript.challenge("x"); - - // Generate nonzero random verifier weights (the randomization already asserts nonzero) - Scalar w1, w2; - w1.randomize(); - w2.randomize(); - - // Reconstruct f-matrix - std::vector f_; - if (!compute_fs(proof, x, f_, n, m)) { - LogPrintf("Invalid matrix reconstruction"); - return false; - } - - // Effective set size - const std::size_t size = sizes[t]; - - // A, B (and associated commitments) - points.emplace_back(proof.A); - scalars.emplace_back(w1.negate()); - points.emplace_back(proof.B); - scalars.emplace_back(x.negate() * w1); - - H_scalar += proof.z * w1; - for (std::size_t i = 0; i < m * n; i++) { - Gi_scalars[i] += f_[i] * w1; - Hi_scalars[i] += f_[i]*(x - f_[i]) * w1; - } - - // Input sets - H_scalar += (proof.zS + bind_weight * proof.zV) * w2.negate(); - - Scalar f_sum; - Scalar f_i(uint64_t(1)); - std::vector::iterator ptr = commit_scalars.begin() + commits.size() - size; - compute_batch_fis(f_sum, f_i, m, f_, w2, ptr, ptr, ptr + size - 1, n); - - Scalar pow(uint64_t(1)); - std::vector f_part_product; - for (std::ptrdiff_t j = m - 1; j >= 0; j--) { - f_part_product.push_back(pow); - pow *= f_[j*n + I_[size - 1][j]]; - } - - Scalar x_powers(uint64_t(1)); - for (std::size_t j = 0; j < m; j++) { - Scalar fi_sum(uint64_t(0)); - for (std::size_t i = I_[size - 1][j] + 1; i < n; i++) - fi_sum += f_[j*n + i]; - pow += fi_sum * x_powers * f_part_product[m - j - 1]; - x_powers *= x; - } - - f_sum += pow; - commit_scalars[commits.size() - 1] += pow * w2; - - // S1, V1 - points.emplace_back(S1[t] + V1[t] * bind_weight); - scalars.emplace_back(f_sum * w2.negate()); - - // (X), (X1) - x_powers = Scalar(uint64_t(1)); - for (std::size_t j = 0; j < m; j++) { - points.emplace_back(proof.X[j] + proof.X1[j] * bind_weight); - scalars.emplace_back(x_powers.negate() * w2); - x_powers *= x; - } - } - - // Add common generators - points.emplace_back(H); - scalars.emplace_back(H_scalar); - for (std::size_t i = 0; i < m * n; i++) { - points.emplace_back(Gi[i]); - scalars.emplace_back(Gi_scalars[i]); - points.emplace_back(Hi[i]); - scalars.emplace_back(Hi_scalars[i]); - } - for (std::size_t i = 0; i < commits.size(); i++) { - points.emplace_back(commits[i]); - scalars.emplace_back(commit_scalars[i]); - } - - // Verify the batch - secp_primitives::MultiExponent result(points, scalars); - if (result.get_multiple().isInfinity()) { - return true; - } - return false; -} - -} \ No newline at end of file diff --git a/src/libspats/grootle.h b/src/libspats/grootle.h deleted file mode 100644 index 735eebc75e..0000000000 --- a/src/libspats/grootle.h +++ /dev/null @@ -1,56 +0,0 @@ -#ifndef FIRO_LIBSPATS_GROOTLE_H -#define FIRO_LIBSPATS_GROOTLE_H - -#include "grootle_proof.h" -#include -#include -#include "util.h" - -namespace spats { - -class Grootle { - -public: - Grootle( - const GroupElement& H, - const std::vector& Gi, - const std::vector& Hi, - const std::size_t n, - const std::size_t m - ); - - void prove(const std::size_t l, - const Scalar& s, - const std::vector& S, - const GroupElement& S1, - const Scalar& v, - const std::vector& V, - const GroupElement& V1, - const std::vector& root, - GrootleProof& proof); - bool verify(const std::vector& S, - const GroupElement& S1, - const std::vector& V, - const GroupElement& V1, - const std::vector& root, - const std::size_t size, - const GrootleProof& proof); // single proof - bool verify(const std::vector& S, - const std::vector& S1, - const std::vector& V, - const std::vector& V1, - const std::vector>& roots, - const std::vector& sizes, - const std::vector& proofs); // batch of proofs - -private: - GroupElement H; - std::vector Gi; - std::vector Hi; - std::size_t n; - std::size_t m; -}; - -} - -#endif diff --git a/src/libspats/grootle_proof.h b/src/libspats/grootle_proof.h deleted file mode 100644 index e68af58f16..0000000000 --- a/src/libspats/grootle_proof.h +++ /dev/null @@ -1,45 +0,0 @@ -#ifndef FIRO_LIBSPATS_GROOTLE_PROOF_H -#define FIRO_LIBSPATS_GROOTLE_PROOF_H - -#include "params.h" - -namespace spats { - -class GrootleProof { -public: - - inline std::size_t memoryRequired() const { - return 2*GroupElement::memoryRequired() + X.size()*GroupElement::memoryRequired() + X1.size()*GroupElement::memoryRequired() + f.size()*Scalar::memoryRequired() + 3*Scalar::memoryRequired(); - } - - inline std::size_t memoryRequired(int n, int m) const { - return 2*GroupElement::memoryRequired() + 2*m*GroupElement::memoryRequired() + m*(n-1)*Scalar::memoryRequired() + 3*Scalar::memoryRequired(); - } - - ADD_SERIALIZE_METHODS; - template - inline void SerializationOp(Stream& s, Operation ser_action) { - READWRITE(A); - READWRITE(B); - READWRITE(X); - READWRITE(X1); - READWRITE(f); - READWRITE(z); - READWRITE(zS); - READWRITE(zV); - } - -public: - GroupElement A; - GroupElement B; - std::vector X; - std::vector X1; - std::vector f; - Scalar z; - Scalar zS; - Scalar zV; -}; - -} - -#endif diff --git a/src/libspats/hash.cpp b/src/libspats/hash.cpp deleted file mode 100644 index 37c6def44b..0000000000 --- a/src/libspats/hash.cpp +++ /dev/null @@ -1,160 +0,0 @@ -#include "hash.h" - -namespace spats { - -using namespace secp_primitives; - -// Set up a labeled hash function -Hash::Hash(const std::string label) { - this->ctx = EVP_MD_CTX_new(); - EVP_DigestInit_ex(this->ctx, EVP_sha512(), NULL); - - // Write the protocol and mode information - std::vector protocol(LABEL_PROTOCOL.begin(), LABEL_PROTOCOL.end()); - EVP_DigestUpdate(this->ctx, protocol.data(), protocol.size()); - EVP_DigestUpdate(this->ctx, &HASH_MODE_FUNCTION, sizeof(HASH_MODE_FUNCTION)); - - // Include the label with size - include_size(label.size()); - std::vector label_bytes(label.begin(), label.end()); - EVP_DigestUpdate(this->ctx, label_bytes.data(), label_bytes.size()); -} - -// Clean up -Hash::~Hash() { - EVP_MD_CTX_free(this->ctx); -} - -// Include serialized data in the hash function -void Hash::include(CDataStream& data) { - include_size(data.size()); - EVP_DigestUpdate(this->ctx, reinterpret_cast(data.data()), data.size()); -} - -// Finalize the hash function to a byte array -std::vector Hash::finalize() { - // Use the full output size of the hash function - std::vector result; - result.resize(EVP_MD_size(EVP_sha512())); - - unsigned int TEMP; - EVP_DigestFinal_ex(this->ctx, result.data(), &TEMP); - - return result; -} - -// Finalize the hash function to a scalar -Scalar Hash::finalize_scalar() { - // Ensure we can properly populate a scalar - if (EVP_MD_size(EVP_sha512()) < SCALAR_ENCODING) { - throw std::runtime_error("Bad hash size!"); - } - - std::vector hash; - hash.resize(EVP_MD_size(EVP_sha512())); - unsigned char counter = 0; - - EVP_MD_CTX* state_counter; - state_counter = EVP_MD_CTX_new(); - EVP_DigestInit_ex(state_counter, EVP_sha512(), NULL); - - EVP_MD_CTX* state_finalize; - state_finalize = EVP_MD_CTX_new(); - EVP_DigestInit_ex(state_finalize, EVP_sha512(), NULL); - - while (1) { - // Prepare temporary state for counter testing - EVP_MD_CTX_copy_ex(state_counter, this->ctx); - - // Embed the counter - EVP_DigestUpdate(state_counter, &counter, sizeof(counter)); - - // Finalize the hash with a temporary state - EVP_MD_CTX_copy_ex(state_finalize, state_counter); - unsigned int TEMP; // We already know the digest length! - EVP_DigestFinal_ex(state_finalize, hash.data(), &TEMP); - - // Check for scalar validity - Scalar candidate; - try { - candidate.deserialize(hash.data()); - - EVP_MD_CTX_free(state_counter); - EVP_MD_CTX_free(state_finalize); - - return candidate; - } catch (...) { - counter++; - } - } -} - -// Finalize the hash function to a group element -GroupElement Hash::finalize_group() { - const int GROUP_ENCODING = 34; - const unsigned char ZERO = 0; - - // Ensure we can properly populate a - if (EVP_MD_size(EVP_sha512()) < GROUP_ENCODING) { - throw std::runtime_error("Bad hash size!"); - } - - std::vector hash; - hash.resize(EVP_MD_size(EVP_sha512())); - unsigned char counter = 0; - - EVP_MD_CTX* state_counter; - state_counter = EVP_MD_CTX_new(); - EVP_DigestInit_ex(state_counter, EVP_sha512(), NULL); - - EVP_MD_CTX* state_finalize; - state_finalize = EVP_MD_CTX_new(); - EVP_DigestInit_ex(state_finalize, EVP_sha512(), NULL); - - while (1) { - // Prepare temporary state for counter testing - EVP_MD_CTX_copy_ex(state_counter, this->ctx); - - // Embed the counter - EVP_DigestUpdate(state_counter, &counter, sizeof(counter)); - - // Finalize the hash with a temporary state - EVP_MD_CTX_copy_ex(state_finalize, state_counter); - unsigned int TEMP; // We already know the digest length! - EVP_DigestFinal_ex(state_finalize, hash.data(), &TEMP); - - // Assemble the serialized input: - // bytes 0..31: x coordinate - // byte 32: even/odd - // byte 33: zero (this point is not infinity) - unsigned char candidate_bytes[GROUP_ENCODING]; - memcpy(candidate_bytes, hash.data(), 33); - memcpy(candidate_bytes + 33, &ZERO, 1); - GroupElement candidate; - try { - candidate.deserialize(candidate_bytes); - - // Deserialization can succeed even with an invalid result - if (!candidate.isMember()) { - counter++; - continue; - } - - EVP_MD_CTX_free(state_counter); - EVP_MD_CTX_free(state_finalize); - - return candidate; - } catch (...) { - counter++; - } - } -} - -// Include a serialized size in the hash function -void Hash::include_size(std::size_t size) { - CDataStream stream(SER_NETWORK, PROTOCOL_VERSION); - stream << (uint64_t)size; - EVP_DigestUpdate(this->ctx, reinterpret_cast(stream.data()), stream.size()); -} - -} \ No newline at end of file diff --git a/src/libspats/hash.h b/src/libspats/hash.h deleted file mode 100644 index 7c68b0ce87..0000000000 --- a/src/libspats/hash.h +++ /dev/null @@ -1,26 +0,0 @@ -#ifndef FIRO_SPATS_HASH_H -#define FIRO_SPATS_HASH_H -#include -#include "util.h" - -namespace spats { - -using namespace secp_primitives; - -class Hash { -public: - Hash(const std::string label); - ~Hash(); - void include(CDataStream& data); - std::vector finalize(); - Scalar finalize_scalar(); - GroupElement finalize_group(); - -private: - void include_size(std::size_t size); - EVP_MD_CTX* ctx; -}; - -} - -#endif diff --git a/src/libspats/kdf.cpp b/src/libspats/kdf.cpp deleted file mode 100644 index 61560895c1..0000000000 --- a/src/libspats/kdf.cpp +++ /dev/null @@ -1,58 +0,0 @@ -#include "kdf.h" - -namespace spats { - -// Set up a labeled KDF -KDF::KDF(const std::string label, std::size_t derived_key_size) { - this->ctx = EVP_MD_CTX_new(); - EVP_DigestInit_ex(this->ctx, EVP_sha512(), NULL); - - // Write the protocol and mode information - std::vector protocol(LABEL_PROTOCOL.begin(), LABEL_PROTOCOL.end()); - EVP_DigestUpdate(this->ctx, protocol.data(), protocol.size()); - EVP_DigestUpdate(this->ctx, &HASH_MODE_KDF, sizeof(HASH_MODE_KDF)); - - // Include the label with size - include_size(label.size()); - std::vector label_bytes(label.begin(), label.end()); - EVP_DigestUpdate(this->ctx, label_bytes.data(), label_bytes.size()); - - // Embed and set the derived key size - if (derived_key_size > EVP_MD_size(EVP_sha512())) { - throw std::invalid_argument("Requested KDF size is too large"); - } - include_size(derived_key_size); - this->derived_key_size = derived_key_size; -} - -// Clean up -KDF::~KDF() { - EVP_MD_CTX_free(this->ctx); -} - -// Include serialized data in the KDF -void KDF::include(CDataStream& data) { - include_size(data.size()); - EVP_DigestUpdate(this->ctx, reinterpret_cast(data.data()), data.size()); -} - -// Finalize the KDF with arbitrary size -std::vector KDF::finalize() { - std::vector result; - result.resize(EVP_MD_size(EVP_sha512())); - - unsigned int TEMP; - EVP_DigestFinal_ex(this->ctx, result.data(), &TEMP); - result.resize(this->derived_key_size); - - return result; -} - -// Include a serialized size in the KDF -void KDF::include_size(std::size_t size) { - CDataStream stream(SER_NETWORK, PROTOCOL_VERSION); - stream << (uint64_t)size; - EVP_DigestUpdate(this->ctx, reinterpret_cast(stream.data()), stream.size()); -} - -} \ No newline at end of file diff --git a/src/libspats/kdf.h b/src/libspats/kdf.h deleted file mode 100644 index d1b9591ba3..0000000000 --- a/src/libspats/kdf.h +++ /dev/null @@ -1,23 +0,0 @@ -#ifndef FIRO_SPATS_KDF_H -#define FIRO_SPATS_KDF_H -#include -#include "util.h" - -namespace spats { - -class KDF { -public: - KDF(const std::string label, std::size_t derived_key_size); - ~KDF(); - void include(CDataStream& data); - std::vector finalize(); - -private: - void include_size(std::size_t size); - EVP_MD_CTX* ctx; - std::size_t derived_key_size; -}; - -} - -#endif diff --git a/src/libspats/keys.cpp b/src/libspats/keys.cpp deleted file mode 100644 index 14b1d0a5e6..0000000000 --- a/src/libspats/keys.cpp +++ /dev/null @@ -1,246 +0,0 @@ -#include "keys.h" -#include "../hash.h" - -namespace spats { - -using namespace secp_primitives; - -SpendKey::SpendKey(const Params* params) { - this->params = params; - this->s1.randomize(); - this->s2.randomize(); - this->r.randomize(); -} - -SpendKey::SpendKey(const Params* params, const Scalar& r_) { - this->params = params; - this->r = r_; - std::vector data; - data.resize(32); - r.serialize(data.data()); - std::vector result(CSHA256().OUTPUT_SIZE); - - CHash256 hash256; - std::string prefix1 = "s1_generation"; - hash256.Write(reinterpret_cast(prefix1.c_str()), prefix1.size()); - hash256.Write(data.data(), data.size()); - hash256.Finalize(&result[0]); - this->s1.memberFromSeed(&result[0]); - - data.clear(); - result.clear(); - hash256.Reset(); - s1.serialize(data.data()); - - std::string prefix2 = "s2_generation"; - hash256.Write(reinterpret_cast(prefix2.c_str()), prefix2.size()); - hash256.Write(data.data(), data.size()); - hash256.Finalize(&result[0]); - this->s2.memberFromSeed(&result[0]); -} - -const Params* SpendKey::get_params() const { - return this->params; -} - -const Scalar& SpendKey::get_s1() const { - return this->s1; -} - -const Scalar& SpendKey::get_s2() const { - return this->s2; -} - -const Scalar& SpendKey::get_r() const { - return this->r; -} - -SpendKey& SpendKey::operator=(const SpendKey& other) { - this->s1 = other.s1; - this->s2 = other.s2; - this->r = other.r; - return *this; -} - -bool SpendKey::operator==(const SpendKey& other) const { - if (this->s1 != other.s1 || - this->s2 != other.s2 || - this->r != other.r) - return false; - return true; -} - -FullViewKey::FullViewKey() {} -FullViewKey::FullViewKey(const Params* params) { - this->params = params; -} -FullViewKey::FullViewKey(const SpendKey& spend_key) { - this->params = spend_key.get_params(); - this->s1 = spend_key.get_s1(); - this->s2 = spend_key.get_s2(); - this->D = this->params->get_G()*spend_key.get_r(); - this->P2 = this->params->get_F()*this->s2 + this->D; -} - -const Params* FullViewKey::get_params() const { - return this->params; -} - -const Scalar& FullViewKey::get_s1() const { - return this->s1; -} - -const Scalar& FullViewKey::get_s2() const { - return this->s2; -} - -const GroupElement& FullViewKey::get_D() const { - return this->D; -} - -const GroupElement& FullViewKey::get_P2() const { - return this->P2; -} - -IncomingViewKey::IncomingViewKey() {} - -IncomingViewKey::IncomingViewKey(const Params* params) { - this->params = params; -} - -IncomingViewKey::IncomingViewKey(const FullViewKey& full_view_key) { - this->params = full_view_key.get_params(); - this->s1 = full_view_key.get_s1(); - this->P2 = full_view_key.get_P2(); -} - -const Params* IncomingViewKey::get_params() const { - return this->params; -} - -const Scalar& IncomingViewKey::get_s1() const { - return this->s1; -} - -const GroupElement& IncomingViewKey::get_P2() const { - return this->P2; -} - -uint64_t IncomingViewKey::get_diversifier(const std::vector& d) const { - // Assert proper size - if (d.size() != AES_BLOCKSIZE) { - throw std::invalid_argument("Bad encrypted diversifier"); - } - - // Decrypt the diversifier; this is NOT AUTHENTICATED and MUST be externally checked for validity against a claimed address - std::vector key = SpatsUtils::kdf_diversifier(this->s1); - uint64_t i = SpatsUtils::diversifier_decrypt(key, d); - - return i; -} - -Address::Address() {} - -Address::Address(const Params* params) { - this->params = params; -} - -Address::Address(const IncomingViewKey& incoming_view_key, const uint64_t i) { - // Encrypt the diversifier - std::vector key = SpatsUtils::kdf_diversifier(incoming_view_key.get_s1()); - this->params = incoming_view_key.get_params(); - this->d = SpatsUtils::diversifier_encrypt(key, i); - this->Q1 = SpatsUtils::hash_div(this->d)*incoming_view_key.get_s1(); - this->Q2 = this->params->get_F()*SpatsUtils::hash_Q2(incoming_view_key.get_s1(), i) + incoming_view_key.get_P2(); -} - -const Params* Address::get_params() const { - return this->params; -} - -const std::vector& Address::get_d() const { - return this->d; -} - -const GroupElement& Address::get_Q1() const { - return this->Q1; -} - -const GroupElement& Address::get_Q2() const { - return this->Q2; -} - -// Encode the address to string, given a network identifier -std::string Address::encode(const unsigned char network) const { - // Serialize the address components - std::vector raw; - raw.reserve(2 * GroupElement::serialize_size + AES_BLOCKSIZE); - - raw.insert(raw.end(), this->d.begin(), this->d.end()); - - std::vector component; - component.resize(GroupElement::serialize_size); - - this->get_Q1().serialize(component.data()); - raw.insert(raw.end(), component.begin(), component.end()); - - this->get_Q2().serialize(component.data()); - raw.insert(raw.end(), component.begin(), component.end()); - - // Apply the scramble encoding and prepend the network byte - std::vector scrambled = F4Grumble(network, raw.size()).encode(raw); - - // Encode using `bech32m` - std::string hrp; - hrp.push_back(ADDRESS_ENCODING_PREFIX); - hrp.push_back(network); - - std::vector bit_converted; - bech32::convertbits(bit_converted, scrambled, 8, 5, true); - - return bech32::encode(hrp, bit_converted, bech32::Encoding::BECH32M); -} - -// Decode an address (if possible) from a string, returning the network identifier -unsigned char Address::decode(const std::string& str) { - // Decode using `bech32m` - bech32::DecodeResult decoded = bech32::decode(str); - - // Check the encoding - if (decoded.encoding != bech32::Encoding::BECH32M) { - throw std::invalid_argument("Bad address encoding"); - } - - // Check the encoding prefix - if (decoded.hrp[0] != ADDRESS_ENCODING_PREFIX) { - throw std::invalid_argument("Bad address prefix"); - } - - // Get the network identifier - unsigned char network = decoded.hrp[1]; - - // Convert the address components to bytes - std::vector scrambled; - bech32::convertbits(scrambled, decoded.data, 5, 8, false); - - // Assert the proper address size - if (scrambled.size() != 2 * GroupElement::serialize_size + AES_BLOCKSIZE) { - throw std::invalid_argument("Bad address size"); - } - - // Apply the scramble decoding - std::vector raw = F4Grumble(network, scrambled.size()).decode(scrambled); - - // Deserialize the adddress components - this->d = std::vector(raw.begin(), raw.begin() + AES_BLOCKSIZE); - - std::vector component(raw.begin() + AES_BLOCKSIZE, raw.begin() + AES_BLOCKSIZE + GroupElement::serialize_size); - this->Q1.deserialize(component.data()); - - component = std::vector(raw.begin() + AES_BLOCKSIZE + GroupElement::serialize_size, raw.end()); - this->Q2.deserialize(component.data()); - - return network; -} - -} diff --git a/src/libspats/keys.h b/src/libspats/keys.h deleted file mode 100644 index b2d6f725c9..0000000000 --- a/src/libspats/keys.h +++ /dev/null @@ -1,95 +0,0 @@ -#ifndef FIRO_SPATS_KEYS_H -#define FIRO_SPATS_KEYS_H -#include "bech32.h" -#include "f4grumble.h" -#include "params.h" -#include "util.h" - -namespace spats { - -using namespace secp_primitives; - -class SpendKey { -public: - SpendKey(const Params* params); - SpendKey(const Params* params, const Scalar& r_); - const Params* get_params() const; - const Scalar& get_s1() const; - const Scalar& get_s2() const; - const Scalar& get_r() const; - - SpendKey& operator=(const SpendKey& other); - bool operator==(const SpendKey& other) const; - -private: - const Params* params; - Scalar s1, s2, r; -}; - -class FullViewKey { -public: - FullViewKey(); - FullViewKey(const Params* params); - FullViewKey(const SpendKey& spend_key); - const Params* get_params() const; - const Scalar& get_s1() const; - const Scalar& get_s2() const; - const GroupElement& get_D() const; - const GroupElement& get_P2() const; - - - ADD_SERIALIZE_METHODS; - template - inline void SerializationOp(Stream& s, Operation ser_action) { - READWRITE(s1); - READWRITE(s2); - READWRITE(D); - READWRITE(P2); - } - -private: - const Params* params; - Scalar s1, s2; - GroupElement D, P2; -}; - -class IncomingViewKey { -public: - IncomingViewKey(); - IncomingViewKey(const Params* params); - IncomingViewKey(const FullViewKey& full_view_key); - const Params* get_params() const; - const Scalar& get_s1() const; - const GroupElement& get_P2() const; - uint64_t get_diversifier(const std::vector& d) const; - -private: - const Params* params; - Scalar s1; - GroupElement P2; -}; - -class Address { -public: - Address(); - Address(const Params* params); - Address(const IncomingViewKey& incoming_view_key, const uint64_t i); - const Params* get_params() const; - const std::vector& get_d() const; - const GroupElement& get_Q1() const; - const GroupElement& get_Q2() const; - - std::string encode(const unsigned char network) const; - unsigned char decode(const std::string& str); - -private: - const Params* params; - std::vector d; - GroupElement Q1, Q2; - - static std::string get_checksum(const std::string data); -}; - -} - -#endif diff --git a/src/libspats/mint_transaction.cpp b/src/libspats/mint_transaction.cpp index ccf98f3acd..9b2dce071b 100644 --- a/src/libspats/mint_transaction.cpp +++ b/src/libspats/mint_transaction.cpp @@ -3,13 +3,13 @@ namespace spats { -MintTransaction::MintTransaction(const Params* params) +MintTransaction::MintTransaction(const spark::Params* params) { this->params = params; } MintTransaction::MintTransaction( - const Params* params, + const spark::Params* params, const std::vector& outputs, const std::vector& serial_context, bool generate) @@ -18,7 +18,7 @@ MintTransaction::MintTransaction( // Important note: For pool transition transactions, the serial context should contain unique references to all base-layer spent assets, in order to ensure the resulting serial commitment is bound to this transaction this->params = params; - Schnorr schnorr(this->params->get_H()); + spark::Schnorr schnorr(this->params->get_H()); std::vector value_statement; std::vector value_witness; @@ -27,10 +27,10 @@ MintTransaction::MintTransaction( if (generate) { MintedCoinData output = outputs[j]; - if (Scalar(output.iota) != Scalar(uint64_t(0)) && output.v != 1) { + if (output.iota != Scalar(uint64_t(0)) && output.v != 1) { throw std::invalid_argument("mint: identifier not equal to 0 and value not equal to 1"); } - if (Scalar(output.a) == Scalar(uint64_t(0)) && Scalar(output.iota) != Scalar(uint64_t(0))) { + if (output.a == Scalar(uint64_t(0)) && output.iota != Scalar(uint64_t(0))) { throw std::invalid_argument("mint: asset type equal to 0 and identifier not equal to 0"); } @@ -51,7 +51,7 @@ MintTransaction::MintTransaction( // Prepare the value proof value_statement.emplace_back(this->coins[j].C + this->params->get_E().inverse() * this->coins[j].a + this->params->get_F().inverse() * this->coins[j].iota + this->params->get_G().inverse() * Scalar(this->coins[j].v)); - value_witness.emplace_back(SpatsUtils::hash_val(k)); + value_witness.emplace_back(spark::SparkUtils::hash_val(k)); } else { Coin coin; coin.type = 0; @@ -67,13 +67,13 @@ MintTransaction::MintTransaction( if (generate) schnorr.prove(value_witness, value_statement, this->value_proof); else - value_proof = SchnorrProof(); + value_proof = spark::SchnorrProof(); } bool MintTransaction::verify() { // Verify the value proof - Schnorr schnorr(this->params->get_H()); + spark::Schnorr schnorr(this->params->get_H()); std::vector value_statement; for (std::size_t j = 0; j < this->coins.size(); j++) { diff --git a/src/libspats/mint_transaction.h b/src/libspats/mint_transaction.h index ba5b6af228..d2a13a10cc 100644 --- a/src/libspats/mint_transaction.h +++ b/src/libspats/mint_transaction.h @@ -1,8 +1,8 @@ #ifndef FIRO_SPATS_MINT_TRANSACTION_H #define FIRO_SPATS_MINT_TRANSACTION_H #include "coin.h" -#include "keys.h" -#include "schnorr.h" +#include "../libspark/keys.h" +#include "../libspark/schnorr.h" #include "util.h" namespace spats @@ -11,7 +11,7 @@ namespace spats using namespace secp_primitives; struct MintedCoinData { - Address address; + spark::Address address; uint64_t v; Scalar a; Scalar iota; @@ -21,9 +21,9 @@ struct MintedCoinData { class MintTransaction { public: - MintTransaction(const Params* params); + MintTransaction(const spark::Params* params); MintTransaction( - const Params* params, + const spark::Params* params, const std::vector& outputs, const std::vector& serial_context, bool generate = true); @@ -38,9 +38,9 @@ class MintTransaction void getCoins(std::vector& coins_); private: - const Params* params; + const spark::Params* params; std::vector coins; - SchnorrProof value_proof; + spark::SchnorrProof value_proof; }; } // namespace spats diff --git a/src/libspats/params.cpp b/src/libspats/params.cpp deleted file mode 100644 index 6af8b588ef..0000000000 --- a/src/libspats/params.cpp +++ /dev/null @@ -1,164 +0,0 @@ -#include "params.h" -#include "chainparams.h" -#include "util.h" - -namespace spats { - - CCriticalSection Params::cs_instance; - std::unique_ptr Params::instance; - -// Protocol parameters for deployment -Params const* Params::get_default() { - if (instance) { - return instance.get(); - } else { - LOCK(cs_instance); - if (instance) { - return instance.get(); - } - - std::size_t memo_bytes = 32; - std::size_t max_M_range = 16; - std::size_t n_grootle = 8; - std::size_t m_grootle = 5; - - instance.reset(new Params(memo_bytes, max_M_range, n_grootle, m_grootle)); - return instance.get(); - } -} - -// Protocol parameters for testing -Params const* Params::get_test() { - if (instance) { - return instance.get(); - } else { - LOCK(cs_instance); - if (instance) { - return instance.get(); - } - - std::size_t memo_bytes = 32; - std::size_t max_M_range = 16; - std::size_t n_grootle = 2; - std::size_t m_grootle = 4; - - instance.reset(new Params(memo_bytes, max_M_range, n_grootle, m_grootle)); - return instance.get(); - } -} - -Params::Params( - const std::size_t memo_bytes, - const std::size_t max_M_range, - const std::size_t n_grootle, - const std::size_t m_grootle -) -{ - // Global generators - this->E = SpatsUtils::hash_generator(LABEL_GENERATOR_E); - this->F = SpatsUtils::hash_generator(LABEL_GENERATOR_F); - this->G.set_base_g(); - this->H = SpatsUtils::hash_generator(LABEL_GENERATOR_H); - this->U = SpatsUtils::hash_generator(LABEL_GENERATOR_U); - - // Coin parameters - this->memo_bytes = memo_bytes; - - // Range proof parameters - this->max_M_range = max_M_range; - this->E_range.resize(64*max_M_range); - this->F_range.resize(64*max_M_range); - this->G_range.resize(64*max_M_range); - this->H_range.resize(64*max_M_range); - for (std::size_t i = 0; i < 64*max_M_range; i++) { - this->G_range[i] = SpatsUtils::hash_generator(LABEL_GENERATOR_G_RANGE + " " + std::to_string(i)); - this->H_range[i] = SpatsUtils::hash_generator(LABEL_GENERATOR_H_RANGE + " " + std::to_string(i)); - } - - // One-of-many parameters - if (n_grootle < 2 || m_grootle < 3) { - throw std::invalid_argument("Bad Grootle parameteres"); - } - this->n_grootle = n_grootle; - this->m_grootle = m_grootle; - this->E_grootle.resize(n_grootle * m_grootle); - this->F_grootle.resize(n_grootle * m_grootle); - this->G_grootle.resize(n_grootle * m_grootle); - this->H_grootle.resize(n_grootle * m_grootle); - for (std::size_t i = 0; i < n_grootle * m_grootle; i++) { - this->E_grootle[i] = SpatsUtils::hash_generator(LABEL_GENERATOR_E_GROOTLE + " " + std::to_string(i)); - this->F_grootle[i] = SpatsUtils::hash_generator(LABEL_GENERATOR_F_GROOTLE + " " + std::to_string(i)); - this->G_grootle[i] = SpatsUtils::hash_generator(LABEL_GENERATOR_G_GROOTLE + " " + std::to_string(i)); - this->H_grootle[i] = SpatsUtils::hash_generator(LABEL_GENERATOR_H_GROOTLE + " " + std::to_string(i)); - } -} - -const GroupElement& Params::get_E() const { - return this->E; -} - -const GroupElement& Params::get_F() const { - return this->F; -} - -const GroupElement& Params::get_G() const { - return this->G; -} - -const GroupElement& Params::get_H() const { - return this->H; -} - -const GroupElement& Params::get_U() const { - return this->U; -} - -const std::size_t Params::get_memo_bytes() const { - return this->memo_bytes; -} - -const std::vector& Params::get_E_range() const { - return this->E_range; -} - -const std::vector& Params::get_F_range() const { - return this->F_range; -} - -const std::vector& Params::get_G_range() const { - return this->G_range; -} - -const std::vector& Params::get_H_range() const { - return this->H_range; -} - -const std::vector& Params::get_E_grootle() const { - return this->E_grootle; -} - -const std::vector& Params::get_F_grootle() const { - return this->F_grootle; -} - -const std::vector& Params::get_G_grootle() const { - return this->G_grootle; -} - -const std::vector& Params::get_H_grootle() const { - return this->H_grootle; -} - -std::size_t Params::get_max_M_range() const { - return this->max_M_range; -} - -std::size_t Params::get_n_grootle() const { - return this->n_grootle; -} - -std::size_t Params::get_m_grootle() const { - return this->m_grootle; -} - -} diff --git a/src/libspats/params.h b/src/libspats/params.h deleted file mode 100644 index 3111cd36f7..0000000000 --- a/src/libspats/params.h +++ /dev/null @@ -1,75 +0,0 @@ -#ifndef FIRO_LIBSPATS_PARAMS_H -#define FIRO_LIBSPATS_PARAMS_H - -#include -#include -#include -#include - -using namespace secp_primitives; - -namespace spats { - -class Params { -public: - static Params const* get_default(); - static Params const* get_test(); - - const GroupElement& get_F() const; - const GroupElement& get_G() const; - const GroupElement& get_H() const; - const GroupElement& get_U() const; - const GroupElement& get_E() const; - - const std::size_t get_memo_bytes() const; - - std::size_t get_max_M_range() const; - const std::vector& get_E_range() const; - const std::vector& get_F_range() const; - const std::vector& get_G_range() const; - const std::vector& get_H_range() const; - - std::size_t get_n_grootle() const; - std::size_t get_m_grootle() const; - const std::vector& get_E_grootle() const; - const std::vector& get_F_grootle() const; - const std::vector& get_G_grootle() const; - const std::vector& get_H_grootle() const; - -private: - Params( - const std::size_t memo_bytes, - const std::size_t max_M_range, - const std::size_t n_grootle, - const std::size_t m_grootle - ); - -private: - static CCriticalSection cs_instance; - static std::unique_ptr instance; - - // Global generators - GroupElement E; - GroupElement F; - GroupElement G; - GroupElement H; - GroupElement U; - - // Coin parameters - std::size_t memo_bytes; - - // Range proof parameters - std::size_t max_M_range; - std::vector E_range, F_range, G_range, H_range; - - // One-of-many parameters - std::size_t n_grootle, m_grootle; - std::vector E_grootle; - std::vector F_grootle; - std::vector G_grootle; - std::vector H_grootle; -}; - -} - -#endif diff --git a/src/libspats/schnorr.cpp b/src/libspats/schnorr.cpp deleted file mode 100644 index 76bb205560..0000000000 --- a/src/libspats/schnorr.cpp +++ /dev/null @@ -1,99 +0,0 @@ -#include "schnorr.h" -#include "transcript.h" - -namespace spats -{ - -Schnorr::Schnorr(const GroupElement& G_) : G(G_) -{ -} - -Scalar Schnorr::challenge( - const std::vector& Y, - const GroupElement& A) -{ - Transcript transcript(LABEL_TRANSCRIPT_SCHNORR); - transcript.add("G", G); - transcript.add("Y", Y); - transcript.add("A", A); - - return transcript.challenge("c"); -} - -void Schnorr::prove(const Scalar& y, const GroupElement& Y, SchnorrProof& proof) -{ - const std::vector y_vector = {y}; - const std::vector Y_vector = {Y}; - prove(y_vector, Y_vector, proof); -} - -void Schnorr::prove(const std::vector& y, const std::vector& Y, SchnorrProof& proof) -{ - const std::size_t n = y.size(); - - // Check statement validity - if (y.size() != Y.size()) { - throw std::invalid_argument("Bad Schnorr statement!1"); - } - - for (std::size_t i = 0; i < n; i++) { - if (G * y[i] != Y[i]) { - throw std::invalid_argument("Bad Schnorr statement!2"); - } - } - - Scalar r; - r.randomize(); - proof.A = G * r; - - const Scalar c = challenge(Y, proof.A); - Scalar c_power(c); - - proof.t = r; - for (std::size_t i = 0; i < n; i++) { - // c_power must be nonzero - if (c_power.isZero()) { - throw std::invalid_argument("Unexpected challenge!"); - } - proof.t += y[i].negate() * c_power; - c_power *= c; - } -} - -bool Schnorr::verify(const GroupElement& Y, const SchnorrProof& proof) -{ - const std::vector Y_vector = {Y}; - return verify(Y_vector, proof); -} - -bool Schnorr::verify(const std::vector& Y, const SchnorrProof& proof) -{ - const std::size_t n = Y.size(); - - std::vector points; - points.reserve(n + 2); - std::vector scalars; - scalars.reserve(n + 2); - - points.emplace_back(G); - scalars.emplace_back(proof.t); - points.emplace_back(proof.A); - scalars.emplace_back(Scalar(uint64_t(1)).negate()); - - const Scalar c = challenge(Y, proof.A); - Scalar c_power(c); - for (std::size_t i = 0; i < n; i++) { - // c_power must be nonzero - if (c_power.isZero()) { - throw std::invalid_argument("Unexpected challenge!"); - } - points.emplace_back(Y[i]); - scalars.emplace_back(c_power); - c_power *= c; - } - - MultiExponent result(points, scalars); - return result.get_multiple().isInfinity(); -} - -} // namespace spats diff --git a/src/libspats/schnorr.h b/src/libspats/schnorr.h deleted file mode 100644 index 63cf623c76..0000000000 --- a/src/libspats/schnorr.h +++ /dev/null @@ -1,25 +0,0 @@ -#ifndef FIRO_LIBSPATS_SCHNORR_H -#define FIRO_LIBSPATS_SCHNORR_H - -#include "schnorr_proof.h" -#include - -namespace spats { - -class Schnorr { -public: - Schnorr(const GroupElement& G); - - void prove(const Scalar& y, const GroupElement& Y, SchnorrProof& proof); - void prove(const std::vector& y, const std::vector& Y, SchnorrProof& proof); - bool verify(const GroupElement& Y, const SchnorrProof& proof); - bool verify(const std::vector& Y, const SchnorrProof& proof); - -private: - Scalar challenge(const std::vector& Y, const GroupElement& A); - const GroupElement& G; -}; - -} - -#endif diff --git a/src/libspats/schnorr_proof.h b/src/libspats/schnorr_proof.h deleted file mode 100644 index 62d891d8d3..0000000000 --- a/src/libspats/schnorr_proof.h +++ /dev/null @@ -1,27 +0,0 @@ -#ifndef FIRO_LIBSPATS_SCHNORR_PROOF_H -#define FIRO_LIBSPATS_SCHNORR_PROOF_H - -#include "params.h" - -namespace spats { - -class SchnorrProof{ -public: - inline std::size_t memoryRequired() const { - return Scalar::memoryRequired() + GroupElement::memoryRequired(); - } - - ADD_SERIALIZE_METHODS; - template - inline void SerializationOp(Stream& s, Operation ser_action) { - READWRITE(A); - READWRITE(t); - } - -public: - GroupElement A; - Scalar t; -}; -} - -#endif diff --git a/src/libspats/spend_transaction.cpp b/src/libspats/spend_transaction.cpp index b641f3ee14..fc0a1ea047 100644 --- a/src/libspats/spend_transaction.cpp +++ b/src/libspats/spend_transaction.cpp @@ -8,16 +8,16 @@ const Scalar ZERO = Scalar((uint64_t)0); // Generate a spend transaction that consumes existing coins and generates new ones SpendTransaction::SpendTransaction( - const Params* params) + const spark::Params* params) { this->params = params; } SpendTransaction::SpendTransaction( - const Params* params, - const FullViewKey& full_view_key, - const SpendKey& spend_key, + const spark::Params* params, + const spark::FullViewKey& full_view_key, + const spark::SpendKey& spend_key, const std::vector& inputs, const std::unordered_map& cover_set_data, const uint64_t f, @@ -25,18 +25,42 @@ SpendTransaction::SpendTransaction( const std::vector& outputs) { this->params = params; - this->inputs = inputs; - this->outputs = outputs; Scalar asset_type; Scalar identifier; // Size parameters - const std::size_t w = inputs.size(); // number of consumed coins + const std::size_t w = inputs.size(); // number of consumed coins const std::size_t t = outputs.size(); // number of generated coins const std::size_t N = (std::size_t)std::pow(params->get_n_grootle(), params->get_m_grootle()); // size of cover sets + bool nonBase = false; + this->inputBase = w; + for (std::size_t i = 0; i < w; ++i) { + if (inputs[i].a != ZERO) { + nonBase = true; + this->inputBase = i; + break; + } else { + if (nonBase) { + throw std::invalid_argument("inputs not sorted, base coins must be at the beginning"); + } + } + } + + nonBase = false; + this->outBase = t; + for (std::size_t i = 0; i < t; ++i) { + if (outputs[i].a != ZERO) { + this->outBase = i; + break; + } else { + if (nonBase) { + throw std::invalid_argument("outputs not sorted, base coins must be at the beginning"); + } + } + } // Prepare input-related vectors this->cover_set_ids.reserve(w); // cover set data and metadata @@ -59,7 +83,7 @@ SpendTransaction::SpendTransaction( std::vector k; // nonces // Prepare inputs - Grootle grootle( + spark::Grootle grootle( this->params->get_H(), this->params->get_G_grootle(), this->params->get_H_grootle(), @@ -87,12 +111,12 @@ SpendTransaction::SpendTransaction( // Serial commitment offset this->S1.emplace_back( - this->params->get_F() * inputs[u].s + this->params->get_H().inverse() * SpatsUtils::hash_ser1(inputs[u].s, full_view_key.get_D()) + full_view_key.get_D()); + this->params->get_F() * inputs[u].s + this->params->get_H().inverse() * spark::SparkUtils::hash_ser1(inputs[u].s, full_view_key.get_D()) + full_view_key.get_D()); // Value commitment offset this->C1.emplace_back( - (this->params->get_E() * inputs[u].a) + (this->params->get_F() * inputs[u].iota) + (this->params->get_G() * Scalar(inputs[u].v)) + (this->params->get_H() * SpatsUtils::hash_val1(inputs[u].s, full_view_key.get_D()))); + (this->params->get_E() * inputs[u].a) + (this->params->get_F() * inputs[u].iota) + (this->params->get_G() * Scalar(inputs[u].v)) + (this->params->get_H() * spark::SparkUtils::hash_val1(inputs[u].s, full_view_key.get_D()))); // Tags @@ -103,10 +127,10 @@ SpendTransaction::SpendTransaction( std::size_t l = inputs[u].index; grootle.prove( l, - SpatsUtils::hash_ser1(inputs[u].s, full_view_key.get_D()), + spark::SparkUtils::hash_ser1(inputs[u].s, full_view_key.get_D()), S, this->S1.back(), - SpatsUtils::hash_val(inputs[u].k) - SpatsUtils::hash_val1(inputs[u].s, full_view_key.get_D()), + spark::SparkUtils::hash_val(inputs[u].k) - spark::SparkUtils::hash_val1(inputs[u].s, full_view_key.get_D()), C, this->C1.back(), this->cover_set_representations[set_id], @@ -115,7 +139,7 @@ SpendTransaction::SpendTransaction( // Chaum data chaum_x.emplace_back(inputs[u].s); chaum_y.emplace_back(spend_key.get_r()); - chaum_z.emplace_back(SpatsUtils::hash_ser1(inputs[u].s, full_view_key.get_D()).negate()); + chaum_z.emplace_back(spark::SparkUtils::hash_ser1(inputs[u].s, full_view_key.get_D()).negate()); } // Generate output coins and prepare range proof vectors @@ -130,9 +154,6 @@ SpendTransaction::SpendTransaction( CDataStream serial_context(SER_NETWORK, PROTOCOL_VERSION); serial_context << this->T; - Scalar iota_out_generic; - Scalar asset_type_out_generic; - for (std::size_t j = 0; j < t; j++) { // Nonce k.emplace_back(); @@ -152,17 +173,11 @@ SpendTransaction::SpendTransaction( std::vector(serial_context.begin(), serial_context.end())); // Range data - range_a.emplace_back(outputs[j].a); range_iota.emplace_back(outputs[j].iota); range_v.emplace_back(outputs[j].v); - range_r.emplace_back(SpatsUtils::hash_val(k.back())); + range_r.emplace_back(spark::SparkUtils::hash_val(k.back())); range_C.emplace_back(this->out_coins.back().C); - - if (outputs[j].a != ZERO) { - iota_out_generic = outputs[j].iota; - asset_type_out_generic = outputs[j].a; - } } // Generate range proof for base coin @@ -193,28 +208,28 @@ SpendTransaction::SpendTransaction( std::vector type_z; for (std::size_t u = 0; u < w; u++) { - if (inputs[u].a == ZERO) { + if (u < this->inputBase) { base_c.emplace_back(C1[u]); base_y.emplace_back(inputs[u].v); - base_z.emplace_back(SpatsUtils::hash_val1(inputs[u].s, full_view_key.get_D())); + base_z.emplace_back(spark::SparkUtils::hash_val1(inputs[u].s, full_view_key.get_D())); } else { type_c.emplace_back(C1[u]); type_y.emplace_back(inputs[u].v); - type_z.emplace_back(SpatsUtils::hash_val1(inputs[u].s, full_view_key.get_D())); + type_z.emplace_back(spark::SparkUtils::hash_val1(inputs[u].s, full_view_key.get_D())); asset_type = inputs[u].a; identifier = inputs[u].iota; } } for (std::size_t j = 0; j < t; j++) { - if (outputs[j].a == ZERO) { + if (j < this->outBase) { base_c.emplace_back(out_coins[j].C); base_y.emplace_back(outputs[j].v); - base_z.emplace_back(SpatsUtils::hash_val(k[j])); + base_z.emplace_back(spark::SparkUtils::hash_val(k[j])); } else { type_c.emplace_back(out_coins[j].C); type_y.emplace_back(outputs[j].v); - type_z.emplace_back(SpatsUtils::hash_val(k[j])); + type_z.emplace_back(spark::SparkUtils::hash_val(k[j])); } } // Generate a proof that all base-type assets @@ -233,7 +248,7 @@ SpendTransaction::SpendTransaction( // Generate the Rep proof - Schnorr schnorr(this->params->get_H()); + spark::Schnorr schnorr(this->params->get_H()); GroupElement rep_statement; Scalar rep_witness; @@ -245,22 +260,22 @@ SpendTransaction::SpendTransaction( uint64_t t_generic = 0; for (std::size_t u = 0; u < w; u++) { - if (inputs[u].a == ZERO) { + if (u < this->inputBase) { rep_statement += C1[u]; - rep_witness += SpatsUtils::hash_val1(inputs[u].s, full_view_key.get_D()); + rep_witness += spark::SparkUtils::hash_val1(inputs[u].s, full_view_key.get_D()); } else { balance_statement += C1[u]; - balance_witness += SpatsUtils::hash_val1(inputs[u].s, full_view_key.get_D()); + balance_witness += spark::SparkUtils::hash_val1(inputs[u].s, full_view_key.get_D()); w_generic++; } } for (std::size_t j = 0; j < t; j++) { - if (outputs[j].a == ZERO) { + if (j < this->outBase) { rep_statement += out_coins[j].C.inverse(); - rep_witness -= SpatsUtils::hash_val(k[j]); + rep_witness -= spark::SparkUtils::hash_val(k[j]); } else { balance_statement += out_coins[j].C.inverse(); - balance_witness -= SpatsUtils::hash_val(k[j]); + balance_witness -= spark::SparkUtils::hash_val(k[j]); t_generic++; } } @@ -296,7 +311,7 @@ SpendTransaction::SpendTransaction( this->balance_proof); // Compute the authorizing Chaum proof - Chaum chaum( + spark::Chaum chaum( this->params->get_F(), this->params->get_G(), this->params->get_H(), @@ -344,7 +359,7 @@ bool SpendTransaction::verify( // NOTE: This assumes that the relationship between a `cover_set_id` and the provided `cover_set` is already valid and canonical! // NOTE: This assumes that validity criteria relating to chain context have been externally checked! bool SpendTransaction::verify( - const Params* params, + const spark::Params* params, const std::vector& transactions, const std::unordered_map >& cover_sets) { @@ -421,7 +436,7 @@ bool SpendTransaction::verify( tx.balance_proof); // Verify the authorizing Chaum-Pedersen proof - Chaum chaum( + spark::Chaum chaum( tx.params->get_F(), tx.params->get_G(), tx.params->get_H(), @@ -430,24 +445,24 @@ bool SpendTransaction::verify( return false; } - TypeEquality type(tx.params->get_E(), tx.params->get_F(), tx.params->get_G(), tx.params->get_H()); BaseAsset base(tx.params->get_G(), tx.params->get_H()); + TypeEquality type(tx.params->get_E(), tx.params->get_F(), tx.params->get_G(), tx.params->get_H()); std::vector type_c; std::vector base_c; for (std::size_t u = 0; u < w; u++) { - if (tx.inputs[u].a != ZERO) { - type_c.emplace_back(tx.C1[u]); - } else { + if (u < tx.inputBase) { base_c.emplace_back(tx.C1[u]); + } else { + type_c.emplace_back(tx.C1[u]); } } for (std::size_t j = 0; j < t; j++) { - if (tx.inputs[j].a != ZERO) { - type_c.emplace_back(tx.out_coins[j].C); - } else { + if (j < tx.outBase) { base_c.emplace_back(tx.out_coins[j].C); + } else { + type_c.emplace_back(tx.out_coins[j].C); } } @@ -460,18 +475,18 @@ bool SpendTransaction::verify( // Verify the balance proof - Schnorr schnorr(tx.params->get_H()); + spark::Schnorr schnorr(tx.params->get_H()); GroupElement rep_statement; GroupElement balance_statement; for (std::size_t u = 0; u < w; u++) { - if (tx.inputs[u].a == ZERO) { + if (u < tx.inputBase) { rep_statement += tx.C1[u]; } else { balance_statement += tx.C1[u]; } } for (std::size_t j = 0; j < t; j++) { - if (tx.outputs[j].a == ZERO) { + if (j < tx.outBase) { rep_statement += tx.out_coins[j].C.inverse(); } else { balance_statement += tx.out_coins[j].C.inverse(); @@ -509,8 +524,7 @@ bool SpendTransaction::verify( // Verify all Grootle proofs in batches (based on cover set) - // TODO: Finish this - Grootle grootle( + spark::Grootle grootle( params->get_H(), params->get_G_grootle(), params->get_H_grootle(), @@ -524,7 +538,7 @@ bool SpendTransaction::verify( std::vector S, S1, V, V1; std::vector > cover_set_representations; std::vector sizes; - std::vector proofs; + std::vector proofs; std::size_t full_cover_set_size = cover_sets.at(cover_set_id).size(); for (std::size_t i = 0; i < full_cover_set_size; i++) { @@ -569,11 +583,11 @@ bool SpendTransaction::verify( std::vector SpendTransaction::hash_bind_inner( const std::unordered_map >& cover_set_representations, const std::vector& C1, - const std::vector& grootle_proofs + const std::vector& grootle_proofs ) { - Hash hash(LABEL_HASH_BIND_INNER); + spark::Hash hash(spark::LABEL_HASH_BIND_INNER); CDataStream stream(SER_NETWORK, PROTOCOL_VERSION); stream << cover_set_representations; stream << S1; @@ -591,13 +605,13 @@ Scalar SpendTransaction::hash_bind( const std::vector hash_bind_inner, const std::vector& out_coins, const uint64_t f_, - const SchnorrProof& rep_proof, + const spark::SchnorrProof& rep_proof, const BPPlusProof& range_proof, const BaseAssetProof& base_proof, const TypeProof& type_proof, const BalanceProof& balance_proof) { - Hash hash(LABEL_HASH_BIND); + spark::Hash hash(spark::LABEL_HASH_BIND); CDataStream stream(SER_NETWORK, PROTOCOL_VERSION); stream << hash_bind_inner; stream << out_coins; diff --git a/src/libspats/spend_transaction.h b/src/libspats/spend_transaction.h index 838c1ce797..ec110ea0af 100644 --- a/src/libspats/spend_transaction.h +++ b/src/libspats/spend_transaction.h @@ -3,11 +3,11 @@ #include "balance.h" #include "base_asset.h" #include "bpplus.h" -#include "chaum.h" +#include "../libspark/chaum.h" #include "coin.h" -#include "grootle.h" -#include "keys.h" -#include "schnorr.h" +#include "../libspark/grootle.h" +#include "../libspark/keys.h" +#include "../libspark/schnorr.h" #include "type.h" #include "util.h" #include @@ -39,7 +39,7 @@ struct CoverSetData { }; struct OutputCoinData { - Address address; + spark::Address address; uint64_t v; std::string memo; Scalar a; // asset type @@ -50,30 +50,30 @@ class SpendTransaction { public: SpendTransaction( - const Params* params); + const spark::Params* params); SpendTransaction( - const Params* params, - const FullViewKey& full_view_key, - const SpendKey& spend_key, - const std::vector& inputs, + const spark::Params* params, + const spark::FullViewKey& full_view_key, + const spark::SpendKey& spend_key, + const std::vector& inputs,//should be sorted, base coins at the beginning, otherwise you will get a failure const std::unordered_map& cover_set_data, const uint64_t f, const uint64_t vout, - const std::vector& outputs); + const std::vector& outputs); //should be sorted, base coins at the beginning, otherwise you will get a failure uint64_t getFee(); const std::vector& getUsedLTags() const; const std::vector& getOutCoins(); const std::vector& getCoinGroupIds(); - static bool verify(const Params* params, const std::vector& transactions, const std::unordered_map >& cover_sets); + static bool verify(const spark::Params* params, const std::vector& transactions, const std::unordered_map >& cover_sets); static bool verify(const SpendTransaction& transaction, const std::unordered_map >& cover_sets); std::vector hash_bind_inner( const std::unordered_map >& cover_set_representations, const std::vector& C1, - const std::vector& grootle_proofs + const std::vector& grootle_proofs // const SchnorrProof& balance_proof, // const BPPlusProof& range_proof ); @@ -81,7 +81,7 @@ class SpendTransaction const std::vector hash_bind_inner, const std::vector& out_coins, const uint64_t f_, - const SchnorrProof& rep_proof, + const spark::SchnorrProof& rep_proof, const BPPlusProof& range_proof, const BaseAssetProof& base_proof, const TypeProof& type_proof, @@ -101,6 +101,11 @@ class SpendTransaction READWRITE(chaum_proof); READWRITE(balance_proof); READWRITE(range_proof); + READWRITE(rep_proof); + READWRITE(base_proof); + READWRITE(type_proof); + READWRITE(inputBase); + READWRITE(outBase); } void setOutCoins(const std::vector& out_coins_) @@ -126,23 +131,23 @@ class SpendTransaction const std::map& getBlockHashes(); private: - const Params* params; + const spark::Params* params; // We need to construct and pass this data before running verification std::unordered_map cover_set_sizes; std::unordered_map > cover_set_representations; std::vector out_coins; + uint64_t vout; // All this data we need to serialize - std::vector inputs; - std::vector outputs; std::map set_id_blockHash; + uint32_t inputBase; + uint32_t outBase; std::vector cover_set_ids; uint64_t f; - uint64_t vout; std::vector S1, C1, T; - std::vector grootle_proofs; - ChaumProof chaum_proof; - SchnorrProof rep_proof; + std::vector grootle_proofs; + spark::ChaumProof chaum_proof; + spark::SchnorrProof rep_proof; BPPlusProof range_proof; BaseAssetProof base_proof; TypeProof type_proof; diff --git a/src/libspats/test/coin_test.cpp b/src/libspats/test/coin_test.cpp index 8c129f11c2..bd6682e284 100644 --- a/src/libspats/test/coin_test.cpp +++ b/src/libspats/test/coin_test.cpp @@ -22,22 +22,23 @@ namespace spats { BOOST_AUTO_TEST_CASE(mint_identify_recover) { // Parameters - const Params* params; - params = Params::get_default(); + const spark::Params* params; + params = spark::Params::get_default(); const Scalar asset_type = Scalar(uint64_t(1)); // new value const Scalar identifier = Scalar(uint64_t(1)); // new value const uint64_t i = 12345; const uint64_t v = 86; - const std::string memo = "Ha Ha Ha"; + const std::string memo = "Spam and eggs are a tasty dish!"; // maximum length + BOOST_CHECK_EQUAL(memo.size(), params->get_memo_bytes()); // Generate keys - SpendKey spend_key(params); - FullViewKey full_view_key(spend_key); - IncomingViewKey incoming_view_key(full_view_key); + spark::SpendKey spend_key(params); + spark::FullViewKey full_view_key(spend_key); + spark::IncomingViewKey incoming_view_key(full_view_key); // Generate address - Address address(incoming_view_key, i); + spark::Address address(incoming_view_key, i); // Generate coin Scalar k; @@ -62,12 +63,11 @@ namespace spats { BOOST_CHECK_EQUAL(i_data.iota, identifier); BOOST_CHECK_EQUAL(i_data.v, v); BOOST_CHECK_EQUAL(i_data.k, k); - BOOST_CHECK_EQUAL(strcmp(memo.c_str(), i_data.memo.c_str()), 0); // compare strings in a lexicographical manner, as we pad the memo in the coin - BOOST_CHECK_EQUAL(i_data.memo.size(), params->get_memo_bytes()); // check that it is padded + BOOST_CHECK_EQUAL(memo, i_data.memo); // Recover coin RecoveredCoinData r_data = coin.recover(full_view_key, i_data); BOOST_CHECK_EQUAL( - params->get_F()*(SpatsUtils::hash_ser(k, coin.serial_context) + SpatsUtils::hash_Q2(incoming_view_key.get_s1(), i) + full_view_key.get_s2()) + full_view_key.get_D(), + params->get_F()*(spark::SparkUtils::hash_ser(k, coin.serial_context) + spark::SparkUtils::hash_Q2(incoming_view_key.get_s1(), i) + full_view_key.get_s2()) + full_view_key.get_D(), params->get_F()*r_data.s + full_view_key.get_D() ); BOOST_CHECK_EQUAL(r_data.T*r_data.s + full_view_key.get_D(), params->get_U()); @@ -76,22 +76,22 @@ namespace spats { BOOST_AUTO_TEST_CASE(spend_identify_recover) { // Parameters - const Params* params; - params = Params::get_default(); + const spark::Params* params; + params = spark::Params::get_default(); const Scalar asset_type = Scalar(uint64_t(0)); // new value const Scalar identifier = Scalar(uint64_t(0)); // new value const uint64_t i = 12345; const uint64_t v = 86; - const std::string memo = "Ha Ha Ha"; + const std::string memo = "Memo"; // Generate keys - SpendKey spend_key(params); - FullViewKey full_view_key(spend_key); - IncomingViewKey incoming_view_key(full_view_key); + spark::SpendKey spend_key(params); + spark::FullViewKey full_view_key(spend_key); + spark::IncomingViewKey incoming_view_key(full_view_key); // Generate address - Address address(incoming_view_key, i); + spark::Address address(incoming_view_key, i); // Generate coin Scalar k; @@ -116,13 +116,12 @@ namespace spats { BOOST_CHECK_EQUAL(i_data.iota, identifier); BOOST_CHECK_EQUAL(i_data.v, v); BOOST_CHECK_EQUAL(i_data.k, k); - BOOST_CHECK_EQUAL(strcmp(memo.c_str(), i_data.memo.c_str()), 0); // compare strings in a lexicographical manner, as we pad the memo in the coin - BOOST_CHECK_EQUAL(i_data.memo.size(), params->get_memo_bytes()); // check that it is padded + BOOST_CHECK_EQUAL(memo.c_str(), i_data.memo.c_str()); // Recover coin RecoveredCoinData r_data = coin.recover(full_view_key, i_data); BOOST_CHECK_EQUAL( - params->get_F()*(SpatsUtils::hash_ser(k, coin.serial_context) + SpatsUtils::hash_Q2(incoming_view_key.get_s1(), i) + full_view_key.get_s2()) + full_view_key.get_D(), + params->get_F()*(spark::SparkUtils::hash_ser(k, coin.serial_context) + spark::SparkUtils::hash_Q2(incoming_view_key.get_s1(), i) + full_view_key.get_s2()) + full_view_key.get_D(), params->get_F()*r_data.s + full_view_key.get_D() ); BOOST_CHECK_EQUAL(r_data.T*r_data.s + full_view_key.get_D(), params->get_U()); diff --git a/src/libspats/test/mint_transaction_test.cpp b/src/libspats/test/mint_transaction_test.cpp index 8cff3a739e..e40200540b 100644 --- a/src/libspats/test/mint_transaction_test.cpp +++ b/src/libspats/test/mint_transaction_test.cpp @@ -34,14 +34,14 @@ BOOST_FIXTURE_TEST_SUITE(spats_mint_transaction_tests, BasicTestingSetup) BOOST_AUTO_TEST_CASE(generate_verify_identifier_zero) { // Parameters - const Params* params; - params = Params::get_default(); + const spark::Params* params; + params = spark::Params::get_default(); const std::size_t t = 4; // number of coins to generate // Generate keys - SpendKey spend_key(params); - FullViewKey full_view_key(spend_key); - IncomingViewKey incoming_view_key(full_view_key); + spark::SpendKey spend_key(params); + spark::FullViewKey full_view_key(spend_key); + spark::IncomingViewKey incoming_view_key(full_view_key); std::vector outputs; @@ -58,7 +58,7 @@ BOOST_AUTO_TEST_CASE(generate_verify_identifier_zero) // Generate addresses and coins for (std::size_t j = 0; j < t; j++) { MintedCoinData output; - output.address = Address(incoming_view_key, 12345 + j); + output.address = spark::Address(incoming_view_key, 12345 + j); output.a = vec_a[j]; output.iota = iota; output.v = vec_v[j]; @@ -80,14 +80,14 @@ BOOST_AUTO_TEST_CASE(generate_verify_identifier_zero) BOOST_AUTO_TEST_CASE(generate_verify_identifier_not_zero) { // Parameters - const Params* params; - params = Params::get_default(); + const spark::Params* params; + params = spark::Params::get_default(); const std::size_t t = 4; // number of coins to generate // Generate keys - SpendKey spend_key(params); - FullViewKey full_view_key(spend_key); - IncomingViewKey incoming_view_key(full_view_key); + spark::SpendKey spend_key(params); + spark::FullViewKey full_view_key(spend_key); + spark::IncomingViewKey incoming_view_key(full_view_key); std::vector> outputs; @@ -104,7 +104,7 @@ BOOST_AUTO_TEST_CASE(generate_verify_identifier_not_zero) // Generate addresses and coins for (std::size_t j = 0; j < t; j++) { MintedCoinData output; - output.address = Address(incoming_view_key, 12345 + j); + output.address = spark::Address(incoming_view_key, 12345 + j); output.a = Scalar(vec_a[j]); output.iota = iota; output.v = vec_v[j]; diff --git a/src/libspats/test/spend_transaction_test.cpp b/src/libspats/test/spend_transaction_test.cpp index ccf1acdac6..a0e3b96f91 100644 --- a/src/libspats/test/spend_transaction_test.cpp +++ b/src/libspats/test/spend_transaction_test.cpp @@ -29,19 +29,19 @@ BOOST_FIXTURE_TEST_SUITE(spats_spend_transaction_tests, BasicTestingSetup) BOOST_AUTO_TEST_CASE(generate_verify) { // Parameters - const Params* params; - params = Params::get_test(); + const spark::Params* params; + params = spark::Params::get_test(); const std::string memo = "Spam and eggs"; // arbitrary memo // Generate keys - SpendKey spend_key(params); - FullViewKey full_view_key(spend_key); - IncomingViewKey incoming_view_key(full_view_key); + spark::SpendKey spend_key(params); + spark::FullViewKey full_view_key(spend_key); + spark::IncomingViewKey incoming_view_key(full_view_key); // Generate address const uint64_t i = 12345; - Address address(incoming_view_key, i); + spark::Address address(incoming_view_key, i); // Mint some coins to the address std::size_t N = (std::size_t)pow(params->get_n_grootle(), params->get_m_grootle()); @@ -127,7 +127,7 @@ BOOST_AUTO_TEST_CASE(generate_verify) f += identified_coin_data.v; } - std::vector spend_indices_generic = {9, 11}; + std::vector spend_indices_generic = {N / 2 + 2, N / 2 + 3}; const std::size_t w_generic = spend_indices_generic.size(); diff --git a/src/libspats/test/tasty.cpp b/src/libspats/test/tasty.cpp index 51e6b94c3f..d47d33eb6d 100644 --- a/src/libspats/test/tasty.cpp +++ b/src/libspats/test/tasty.cpp @@ -27,7 +27,7 @@ BOOST_AUTO_TEST_CASE(generate_verify) // Parameters - const Params* params; + const spark::Params* params; params = Params::get_default(); outputFile << "Hello, World!\n"; diff --git a/src/libspats/transcript.cpp b/src/libspats/transcript.cpp deleted file mode 100644 index 302b4e5cfe..0000000000 --- a/src/libspats/transcript.cpp +++ /dev/null @@ -1,177 +0,0 @@ -#include "transcript.h" - -namespace spats { - -using namespace secp_primitives; - -// Flags for transcript operations -const unsigned char FLAG_DOMAIN = 0; -const unsigned char FLAG_DATA = 1; -const unsigned char FLAG_VECTOR = 2; -const unsigned char FLAG_CHALLENGE = 3; - -// Initialize a transcript with a domain separator -Transcript::Transcript(const std::string domain) { - // Prepare the state - this->ctx = EVP_MD_CTX_new(); - EVP_DigestInit_ex(this->ctx, EVP_sha512(), NULL); - - // Write the protocol and mode information - std::vector protocol(LABEL_PROTOCOL.begin(), LABEL_PROTOCOL.end()); - EVP_DigestUpdate(this->ctx, protocol.data(), protocol.size()); - EVP_DigestUpdate(this->ctx, &HASH_MODE_TRANSCRIPT, sizeof(HASH_MODE_TRANSCRIPT)); - - // Domain separator - include_flag(FLAG_DOMAIN); - include_label(domain); -} - -Transcript::~Transcript() { - EVP_MD_CTX_free(this->ctx); -} - -Transcript& Transcript::operator=(const Transcript& t) { - if (this == &t) { - return *this; - } - - EVP_MD_CTX_copy_ex(this->ctx, t.ctx); - - return *this; -} - -// Add a group element -void Transcript::add(const std::string label, const GroupElement& group_element) { - std::vector data; - data.resize(GroupElement::serialize_size); - group_element.serialize(data.data()); - - include_flag(FLAG_DATA); - include_label(label); - include_data(data); -} - -// Add a vector of group elements -void Transcript::add(const std::string label, const std::vector& group_elements) { - include_flag(FLAG_VECTOR); - size(group_elements.size()); - include_label(label); - for (std::size_t i = 0; i < group_elements.size(); i++) { - std::vector data; - data.resize(GroupElement::serialize_size); - group_elements[i].serialize(data.data()); - include_data(data); - } -} - -// Add a scalar -void Transcript::add(const std::string label, const Scalar& scalar) { - std::vector data; - data.resize(SCALAR_ENCODING); - scalar.serialize(data.data()); - - include_flag(FLAG_DATA); - include_label(label); - include_data(data); -} - -// Add a vector of scalars -void Transcript::add(const std::string label, const std::vector& scalars) { - include_flag(FLAG_VECTOR); - size(scalars.size()); - include_label(label); - for (std::size_t i = 0; i < scalars.size(); i++) { - std::vector data; - data.resize(SCALAR_ENCODING); - scalars[i].serialize(data.data()); - include_data(data); - } -} - -// Add arbitrary data -void Transcript::add(const std::string label, const std::vector& data) { - include_flag(FLAG_DATA); - include_label(label); - include_data(data); -} - -// Produce a challenge -Scalar Transcript::challenge(const std::string label) { - // Ensure we can properly populate a scalar - if (EVP_MD_size(EVP_sha512()) < SCALAR_ENCODING) { - throw std::runtime_error("Bad hash size!"); - } - - std::vector hash; - hash.resize(EVP_MD_size(EVP_sha512())); - unsigned char counter = 0; - - EVP_MD_CTX* state_counter; - state_counter = EVP_MD_CTX_new(); - EVP_DigestInit_ex(state_counter, EVP_sha512(), NULL); - - EVP_MD_CTX* state_finalize; - state_finalize = EVP_MD_CTX_new(); - EVP_DigestInit_ex(state_finalize, EVP_sha512(), NULL); - - include_flag(FLAG_CHALLENGE); - include_label(label); - - while (1) { - // Prepare temporary state for counter testing - EVP_MD_CTX_copy_ex(state_counter, this->ctx); - - // Embed the counter - EVP_DigestUpdate(state_counter, &counter, sizeof(counter)); - - // Finalize the hash with a temporary state - EVP_MD_CTX_copy_ex(state_finalize, state_counter); - unsigned int TEMP; // We already know the digest length! - EVP_DigestFinal_ex(state_finalize, hash.data(), &TEMP); - - // Check for scalar validity - Scalar candidate; - try { - candidate.deserialize(hash.data()); - EVP_MD_CTX_copy_ex(this->ctx, state_counter); - - EVP_MD_CTX_free(state_counter); - EVP_MD_CTX_free(state_finalize); - - return candidate; - } catch (...) { - counter++; - } - } -} - -// Encode and include a size -void Transcript::size(const std::size_t size_) { - Scalar size_scalar(size_); - std::vector size_data; - size_data.resize(SCALAR_ENCODING); - size_scalar.serialize(size_data.data()); - EVP_DigestUpdate(this->ctx, size_data.data(), size_data.size()); -} - -// Include a flag -void Transcript::include_flag(const unsigned char flag) { - EVP_DigestUpdate(this->ctx, &flag, sizeof(flag)); -} - -// Encode and include a label -void Transcript::include_label(const std::string label) { - std::vector bytes(label.begin(), label.end()); - include_data(bytes); -} - -// Encode and include data -void Transcript::include_data(const std::vector& data) { - // Include size - size(data.size()); - - // Include data - EVP_DigestUpdate(this->ctx, data.data(), data.size()); -} - -} diff --git a/src/libspats/transcript.h b/src/libspats/transcript.h deleted file mode 100644 index 07680424d3..0000000000 --- a/src/libspats/transcript.h +++ /dev/null @@ -1,32 +0,0 @@ -#ifndef FIRO_SPATS_TRANSCRIPT_H -#define FIRO_SPATS_TRANSCRIPT_H -#include -#include "util.h" - -namespace spats { - -using namespace secp_primitives; - -class Transcript { -public: - Transcript(const std::string); - Transcript& operator=(const Transcript&); - ~Transcript(); - void add(const std::string, const Scalar&); - void add(const std::string, const std::vector&); - void add(const std::string, const GroupElement&); - void add(const std::string, const std::vector&); - void add(const std::string, const std::vector&); - Scalar challenge(const std::string); - -private: - void size(const std::size_t size_); - void include_flag(const unsigned char); - void include_label(const std::string); - void include_data(const std::vector&); - EVP_MD_CTX* ctx; -}; - -} - -#endif diff --git a/src/libspats/type.cpp b/src/libspats/type.cpp index 62b5fa8c16..47e944e217 100644 --- a/src/libspats/type.cpp +++ b/src/libspats/type.cpp @@ -1,5 +1,6 @@ #include "type.h" -#include "transcript.h" +#include "../libspark/transcript.h" +#include "util.h" namespace spats { @@ -12,7 +13,7 @@ Scalar TypeEquality::challenge( const GroupElement& A, const GroupElement& B) { - Transcript transcript(LABEL_TRANSCRIPT_TYPE); + spark::Transcript transcript(LABEL_TRANSCRIPT_TYPE); transcript.add("E", E); transcript.add("F", F); transcript.add("G", G); @@ -97,28 +98,12 @@ bool TypeEquality::verify(const std::vector& C, const TypeProof& p { // GroupElement tempC2; const std::size_t n = C.size(); - - // std::vector points; - // points.reserve(n + 2); - // std::vector scalars; - // scalars.reserve(n + 2); const Scalar c = challenge(C, proof.A, proof.B); // c must be nonzero if (c.isZero()) { throw std::invalid_argument("Unexpected challenge!"); } - // Scalar c_power(c); - const GroupElement check1 = (proof.A + C[0] * c) + (E * proof.tw + F * proof.tx + G * proof.ty + H * proof.tz).inverse(); - // for (std::size_t i = 1; i < n; i++) { - // // c_power must be nonzero - // if (c_power.isZero()) { - // throw std::invalid_argument("Unexpected challenge!"); - // } - // tempC2 += (C[i] + C[0].inverse()) * c_power; - // c_power *= c; - // } - // const GroupElement check2 = (proof.B + tempC2) + (G * proof.uy + H * proof.uz).inverse(); // equation 1 // tw * E + tx * F + ty * G + tz * H = A + c * C0 @@ -157,26 +142,19 @@ bool TypeEquality::verify(const std::vector& C, const TypeProof& p scalars_eq_2.emplace_back(c_power); points_eq_2.emplace_back(C[i] + C[0].inverse()); - // tempC2 += (C[i] + C[0].inverse()) * c_power; c_power *= c; } scalars_eq_2.emplace_back(1); scalars_eq_2.emplace_back(proof.uy); scalars_eq_2.emplace_back(proof.uz); - points_eq_2.emplace_back(proof.B); points_eq_2.emplace_back(G.inverse()); points_eq_2.emplace_back(H.inverse()); - // const GroupElement check2 = (proof.B + tempC2) + (G * proof.uy + H * proof.uz).inverse(); - MultiExponent result_eq_1(points_eq_1, scalars_eq_1); MultiExponent result_eq_2(points_eq_2, scalars_eq_2); - // return result.get_multiple().isInfinity(); - return result_eq_1.get_multiple().isInfinity() && result_eq_2.get_multiple().isInfinity(); - // return check1.isInfinity() && check2.isInfinity(); } diff --git a/src/libspats/type_proof.h b/src/libspats/type_proof.h index 80741bfdb6..01cece1bc3 100644 --- a/src/libspats/type_proof.h +++ b/src/libspats/type_proof.h @@ -1,7 +1,7 @@ #ifndef FIRO_LIBSPATS_TYPE_PROOF_H #define FIRO_LIBSPATS_TYPE_PROOF_H -#include "params.h" +#include "../libspark/params.h" #include namespace spats diff --git a/src/libspats/util.cpp b/src/libspats/util.cpp deleted file mode 100644 index 5df97a28b2..0000000000 --- a/src/libspats/util.cpp +++ /dev/null @@ -1,249 +0,0 @@ -#include "util.h" - -namespace spats { - -using namespace secp_primitives; - -// Encrypt a diversifier using AES-256 -std::vector SpatsUtils::diversifier_encrypt(const std::vector& key, const uint64_t i) { - // Serialize the diversifier - CDataStream i_stream(SER_NETWORK, PROTOCOL_VERSION); - i_stream << i; - - // Assert proper sizes - if (key.size() != AES256_KEYSIZE) { - throw std::invalid_argument("Bad diversifier encryption key size"); - } - - // Encrypt using padded AES-256 (CBC) using a zero IV - std::vector ciphertext; - ciphertext.resize(AES_BLOCKSIZE); - std::vector iv; - iv.resize(AES_BLOCKSIZE); - - AES256CBCEncrypt aes(key.data(), iv.data(), true); - std::vector plaintext; - plaintext.insert(plaintext.begin(), i_stream.begin(), i_stream.end()); - plaintext.resize(AES_BLOCKSIZE); - aes.Encrypt(plaintext.data(), i_stream.size(), ciphertext.data()); - - return ciphertext; -} - -// Decrypt a diversifier using AES-256 -uint64_t SpatsUtils::diversifier_decrypt(const std::vector& key, const std::vector& d) { - // Assert proper sizes - if (key.size() != AES256_KEYSIZE) { - throw std::invalid_argument("Bad diversifier decryption key size"); - } - - std::vector iv; - iv.resize(AES_BLOCKSIZE); - - AES256CBCDecrypt aes(key.data(), iv.data(), true); - std::vector plaintext; - plaintext.resize(AES_BLOCKSIZE); - aes.Decrypt(d.data(), d.size(), plaintext.data()); - - // Decrypt using padded AES-256 (CBC) using a zero IV - CDataStream i_stream(SER_NETWORK, PROTOCOL_VERSION); - i_stream.write((const char *)plaintext.data(), sizeof(uint64_t)); - // Deserialize the diversifier - uint64_t i; - i_stream >> i; - - return i; -} - -// Produce a uniformly-sampled group element from a label -GroupElement SpatsUtils::hash_generator(const std::string label) { - const int GROUP_ENCODING = 34; - const unsigned char ZERO = 0; - - // Ensure we can properly populate a group element encoding - if (EVP_MD_size(EVP_sha512()) < GROUP_ENCODING) { - throw std::runtime_error("Bad hash size!"); - } - - EVP_MD_CTX* ctx; - ctx = EVP_MD_CTX_new(); - EVP_DigestInit_ex(ctx, EVP_sha512(), NULL); - - // Write the protocol and mode - std::vector protocol(LABEL_PROTOCOL.begin(), LABEL_PROTOCOL.end()); - EVP_DigestUpdate(ctx, protocol.data(), protocol.size()); - EVP_DigestUpdate(ctx, &HASH_MODE_GROUP_GENERATOR, sizeof(HASH_MODE_GROUP_GENERATOR)); - - // Write the label - std::vector bytes(label.begin(), label.end()); - EVP_DigestUpdate(ctx, bytes.data(), bytes.size()); - - std::vector hash; - hash.resize(EVP_MD_size(EVP_sha512())); - unsigned char counter = 0; - - EVP_MD_CTX* state_counter; - state_counter = EVP_MD_CTX_new(); - EVP_DigestInit_ex(state_counter, EVP_sha512(), NULL); - - EVP_MD_CTX* state_finalize; - state_finalize = EVP_MD_CTX_new(); - EVP_DigestInit_ex(state_finalize, EVP_sha512(), NULL); - - // Finalize the hash - while (1) { - // Prepare temporary state for counter testing - EVP_MD_CTX_copy_ex(state_counter, ctx); - - // Embed the counter - EVP_DigestUpdate(state_counter, &counter, sizeof(counter)); - - // Finalize the hash with a temporary state - EVP_MD_CTX_copy_ex(state_finalize, state_counter); - unsigned int TEMP; // We already know the digest length! - EVP_DigestFinal_ex(state_finalize, hash.data(), &TEMP); - - // Assemble the serialized input: - // bytes 0..31: x coordinate - // byte 32: even/odd - // byte 33: zero (this point is not infinity) - unsigned char candidate_bytes[GROUP_ENCODING]; - memcpy(candidate_bytes, hash.data(), 33); - memcpy(candidate_bytes + 33, &ZERO, 1); - GroupElement candidate; - try { - candidate.deserialize(candidate_bytes); - - // Deserialization can succeed even with an invalid result - if (!candidate.isMember()) { - counter++; - continue; - } - - EVP_MD_CTX_free(ctx); - EVP_MD_CTX_free(state_counter); - EVP_MD_CTX_free(state_finalize); - - return candidate; - } catch (...) { - counter++; - } - } -} - -// Derive an AES key for diversifier encryption/decryption -std::vector SpatsUtils::kdf_diversifier(const Scalar& s1) { - KDF kdf(LABEL_KDF_DIVERSIFIER, AES256_KEYSIZE); - - CDataStream stream(SER_NETWORK, PROTOCOL_VERSION); - stream << s1; - kdf.include(stream); - - return kdf.finalize(); -} - -// Derive a ChaCha20 key for AEAD operations -std::vector SpatsUtils::kdf_aead(const GroupElement& K_der) { - KDF kdf(LABEL_KDF_AEAD, AEAD_KEY_SIZE); - - CDataStream stream(SER_NETWORK, PROTOCOL_VERSION); - stream << K_der; - kdf.include(stream); - - return kdf.finalize(); -} - -// Derive a ChaCha20 key commitment for AEAD operations -std::vector SpatsUtils::commit_aead(const GroupElement& K_der) { - // We use a KDF here because of the output size - KDF kdf(LABEL_COMMIT_AEAD, AEAD_COMMIT_SIZE); - - CDataStream stream(SER_NETWORK, PROTOCOL_VERSION); - stream << K_der; - kdf.include(stream); - - return kdf.finalize(); -} - -// Hash-to-group function H_div -GroupElement SpatsUtils::hash_div(const std::vector& d) { - Hash hash(LABEL_HASH_DIV); - - CDataStream stream(SER_NETWORK, PROTOCOL_VERSION); - stream << d; - hash.include(stream); - - return hash.finalize_group(); -} - -// Hash-to-scalar function H_Q2 -Scalar SpatsUtils::hash_Q2(const Scalar& s1, const Scalar& i) { - Hash hash(LABEL_HASH_Q2); - - CDataStream stream(SER_NETWORK, PROTOCOL_VERSION); - stream << s1; - stream << i; - hash.include(stream); - - return hash.finalize_scalar(); -} - -// Hash-to-scalar function H_k -Scalar SpatsUtils::hash_k(const Scalar& k) { - Hash hash(LABEL_HASH_K); - - CDataStream stream(SER_NETWORK, PROTOCOL_VERSION); - stream << k; - hash.include(stream); - - return hash.finalize_scalar(); -} - -// Hash-to-scalar function H_ser -Scalar SpatsUtils::hash_ser(const Scalar& k, const std::vector& serial_context) { - Hash hash(LABEL_HASH_SER); - - CDataStream stream(SER_NETWORK, PROTOCOL_VERSION); - stream << k; - stream << serial_context; - hash.include(stream); - - return hash.finalize_scalar(); -} - -// Hash-to-scalar function H_val -Scalar SpatsUtils::hash_val(const Scalar& k) { - Hash hash(LABEL_HASH_VAL); - - CDataStream stream(SER_NETWORK, PROTOCOL_VERSION); - stream << k; - hash.include(stream); - - return hash.finalize_scalar(); -} - -// Hash-to-scalar function H_ser1 -Scalar SpatsUtils::hash_ser1(const Scalar& s, const GroupElement& D) { - Hash hash(LABEL_HASH_SER1); - - CDataStream stream(SER_NETWORK, PROTOCOL_VERSION); - stream << s; - stream << D; - hash.include(stream); - - return hash.finalize_scalar(); -} - -// Hash-to-scalar function H_val1 -Scalar SpatsUtils::hash_val1(const Scalar& s, const GroupElement& D) { - Hash hash(LABEL_HASH_VAL1); - - CDataStream stream(SER_NETWORK, PROTOCOL_VERSION); - stream << s; - stream << D; - hash.include(stream); - - return hash.finalize_scalar(); -} - -} diff --git a/src/libspats/util.h b/src/libspats/util.h index 3167a0cc47..ecfbbe6021 100644 --- a/src/libspats/util.h +++ b/src/libspats/util.h @@ -6,11 +6,11 @@ #include "../streams.h" #include "../util.h" #include "../version.h" -#include "hash.h" -#include "kdf.h" +#include "../libspark/hash.h" +#include "../libspark/kdf.h" +#include "../libspark/util.h" -namespace spats -{ +namespace spats { using namespace secp_primitives; @@ -18,96 +18,10 @@ using namespace secp_primitives; const std::size_t SCALAR_ENCODING = 32; // Base protocol separator -const std::string LABEL_PROTOCOL = "SPATS"; - -// All hash operations have a mode flag to separate their use cases -const unsigned char HASH_MODE_TRANSCRIPT = 0; // a Fiat-Shamir transcript -const unsigned char HASH_MODE_GROUP_GENERATOR = 1; // a prime-order group generator derived from a label -const unsigned char HASH_MODE_FUNCTION = 2; // a hash function derived from a label -const unsigned char HASH_MODE_KDF = 3; // a key derivation function derived from a label - -// Transcript labels -const std::string LABEL_TRANSCRIPT_BPPLUS = "BULLETPROOF_PLUS_V1"; -const std::string LABEL_TRANSCRIPT_CHAUM = "CHAUM_V1"; -const std::string LABEL_TRANSCRIPT_GROOTLE = "GROOTLE_V1"; -const std::string LABEL_TRANSCRIPT_SCHNORR = "SCHNORR_V1"; +const std::string LABEL_TRANSCRIPT_BPPLUS = "BULLETPROOF_PLUS_V2"; const std::string LABEL_TRANSCRIPT_BASE = "BASE_ASSET_V1"; const std::string LABEL_TRANSCRIPT_TYPE = "TYPEEQUALITY_V1"; const std::string LABEL_TRANSCRIPT_BALANCE = "BALANCE_V1"; - -// Generator labels -const std::string LABEL_GENERATOR_E = "E"; -const std::string LABEL_GENERATOR_F = "F"; -const std::string LABEL_GENERATOR_H = "H"; -const std::string LABEL_GENERATOR_U = "U"; -const std::string LABEL_GENERATOR_E_RANGE = "E_RANGE"; -const std::string LABEL_GENERATOR_F_RANGE = "F_RANGE"; -const std::string LABEL_GENERATOR_G_RANGE = "G_RANGE"; -const std::string LABEL_GENERATOR_H_RANGE = "H_RANGE"; -const std::string LABEL_GENERATOR_E_GROOTLE = "E_GROOTLE"; -const std::string LABEL_GENERATOR_F_GROOTLE = "F_GROOTLE"; -const std::string LABEL_GENERATOR_G_GROOTLE = "G_GROOTLE"; -const std::string LABEL_GENERATOR_H_GROOTLE = "H_GROOTLE"; - -// Hash function labels -const std::string LABEL_HASH_DIV = "DIV"; -const std::string LABEL_HASH_Q2 = "Q2"; -const std::string LABEL_HASH_K = "K"; -const std::string LABEL_HASH_SER = "SER"; -const std::string LABEL_HASH_VAL = "VAL"; -const std::string LABEL_HASH_SER1 = "SER1"; -const std::string LABEL_HASH_VAL1 = "VAL1"; -const std::string LABEL_HASH_BIND_INNER = "BIND_INNER"; -const std::string LABEL_HASH_BIND = "BIND"; -const std::string LABEL_F4GRUMBLE_G = "SPATS_F4GRUMBLE_G"; -const std::string LABEL_F4GRUMBLE_H = "SPATS_F4GRUMBLE_H"; - -// KDF labels -const std::string LABEL_KDF_DIVERSIFIER = "DIVERSIFIER"; -const std::string LABEL_KDF_AEAD = "AEAD"; -const std::string LABEL_COMMIT_AEAD = "COMMIT_AEAD"; - -// AEAD constants -const int AEAD_IV_SIZE = 12; // byte length of the IV -const int AEAD_KEY_SIZE = 32; // byte length of the key -const int AEAD_TAG_SIZE = 16; // byte length of the tag -const int AEAD_COMMIT_SIZE = 32; // byte length of the key commitment - -// Address encoding prefix -const unsigned char ADDRESS_ENCODING_PREFIX = 's'; - -// Address encoding network identifiers -// TODO: Extend/update/replace these as needed! These are just initial examples -const unsigned char ADDRESS_NETWORK_MAINNET = 'm'; -const unsigned char ADDRESS_NETWORK_TESTNET = 't'; -const unsigned char ADDRESS_NETWORK_REGTEST = 'r'; -const unsigned char ADDRESS_NETWORK_DEVNET = 'd'; - -class SpatsUtils -{ -public: - // Protocol-level hash functions - static GroupElement hash_generator(const std::string label); - - // Hash functions - static GroupElement hash_div(const std::vector& d); - static Scalar hash_Q2(const Scalar& s1, const Scalar& i); - static Scalar hash_k(const Scalar& k); - static Scalar hash_ser(const Scalar& k, const std::vector& serial_context); - static Scalar hash_val(const Scalar& k); - static Scalar hash_ser1(const Scalar& s, const GroupElement& D); - static Scalar hash_val1(const Scalar& s, const GroupElement& D); - - // Key derivation functions - static std::vector kdf_diversifier(const Scalar& s1); - static std::vector kdf_aead(const GroupElement& K_der); - static std::vector commit_aead(const GroupElement& K_der); - - // Diversifier encryption/decryption - static std::vector diversifier_encrypt(const std::vector& key, const uint64_t i); - static uint64_t diversifier_decrypt(const std::vector& key, const std::vector& d); -}; - } // namespace spats #endif diff --git a/src/wallet.backup b/src/wallet.backup deleted file mode 100644 index c50d9a18c7..0000000000 --- a/src/wallet.backup +++ /dev/null @@ -1,8 +0,0 @@ -# Wallet dump created by Firo v0.14.12.4-66e7ec14a -# * Created on 2023-12-06T14:55:30Z -# * Best block at time of backup was 103 (38653957c4a231a6dfb3e81c2fedb23c7a1f42f572bd2a9871953de089958c30), -# mined on 2023-12-06T14:55:30Z - -cQQ2SjT5Bk8rMDwpiPcq5PRokF3hY7KovaL9wXjs61iUXkWqTGXA 2023-12-06T14:55:30Z change=1 # addr=TDyiJ3miPZQ4i2g1tthi4UQBSvohuffguy - -# End of dump