From 63fe35d5c511dfc94613ddd333dff81cf651a55e Mon Sep 17 00:00:00 2001 From: sowle Date: Sun, 20 Mar 2022 03:09:28 +0300 Subject: [PATCH 01/15] warning fix in threads pool --- src/common/threads_pool.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/common/threads_pool.h b/src/common/threads_pool.h index 4e4e3905..b23c15b5 100644 --- a/src/common/threads_pool.h +++ b/src/common/threads_pool.h @@ -55,7 +55,7 @@ namespace utils { m_is_stop = false; - for (int i = 0; i < num_threads; i++) + for (unsigned int i = 0; i < num_threads; i++) { m_threads.push_back(std::thread([this]() {this->worker_func(); })); } From b6fca25a1026a27743a140d193421e6664ca3519 Mon Sep 17 00:00:00 2001 From: sowle Date: Sun, 20 Mar 2022 03:22:46 +0300 Subject: [PATCH 02/15] boost placeholders fix --- tests/core_tests/chaingen.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/core_tests/chaingen.h b/tests/core_tests/chaingen.h index 7cbf4822..e6b9fb02 100644 --- a/tests/core_tests/chaingen.h +++ b/tests/core_tests/chaingen.h @@ -997,10 +997,10 @@ void append_vector_by_another_vector(U& dst, const V& src) #define REGISTER_CALLBACK(CB_NAME, CLBACK) \ - register_callback(CB_NAME, boost::bind(&CLBACK, this, _1, _2, _3)); + register_callback(CB_NAME, boost::bind(&CLBACK, this, boost::placeholders::_1, boost::placeholders::_2, boost::placeholders::_3)) #define REGISTER_CALLBACK_METHOD(CLASS, METHOD) \ - register_callback(#METHOD, boost::bind(&CLASS::METHOD, this, _1, _2, _3)); + register_callback(#METHOD, boost::bind(&CLASS::METHOD, this, boost::placeholders::_1, boost::placeholders::_2, boost::placeholders::_3)) #define MAKE_GENESIS_BLOCK(VEC_EVENTS, BLK_NAME, MINER_ACC, TS) \ test_generator generator; \ From 02544f718657b314df856f972207b391fa58b13b Mon Sep 17 00:00:00 2001 From: sowle Date: Sun, 20 Mar 2022 04:05:15 +0300 Subject: [PATCH 03/15] boost placeholders fix (2) --- .../epee/include/net/abstract_tcp_server2.inl | 2 +- .../include/storages/levin_abstract_invoke2.h | 8 +- src/common/ntp.cpp | 2 +- src/daemon/daemon_commands_handler.h | 87 ++++++++++--------- src/simplewallet/simplewallet.cpp | 77 ++++++++-------- 5 files changed, 90 insertions(+), 86 deletions(-) diff --git a/contrib/epee/include/net/abstract_tcp_server2.inl b/contrib/epee/include/net/abstract_tcp_server2.inl index 2bb45f69..6829b645 100644 --- a/contrib/epee/include/net/abstract_tcp_server2.inl +++ b/contrib/epee/include/net/abstract_tcp_server2.inl @@ -693,7 +693,7 @@ bool boosted_tcp_server::connect(const std::string& adr, con shared_context->cond.notify_one(); }; - sock_.async_connect(remote_endpoint, boost::bind(connect_callback, _1, local_shared_context)); + sock_.async_connect(remote_endpoint, boost::bind(connect_callback, boost::placeholders::_1, local_shared_context)); while(local_shared_context->ec == boost::asio::error::would_block) { bool r = false; try { diff --git a/contrib/epee/include/storages/levin_abstract_invoke2.h b/contrib/epee/include/storages/levin_abstract_invoke2.h index 1b2c74a4..4c1c5569 100644 --- a/contrib/epee/include/storages/levin_abstract_invoke2.h +++ b/contrib/epee/include/storages/levin_abstract_invoke2.h @@ -267,20 +267,20 @@ namespace epee #define HANDLE_INVOKE2(command_id, func, type_name_in, typename_out) \ if(!is_notify && command_id == command) \ - {handled=true;return epee::net_utils::buff_to_t_adapter(this, command, in_buff, buff_out, boost::bind(func, this, _1, _2, _3, _4), context);} + {handled=true;return epee::net_utils::buff_to_t_adapter(this, command, in_buff, buff_out, boost::bind(func, this, boost::placeholders::_1, boost::placeholders::_2, boost::placeholders::_3, boost::placeholders::_4), context);} #define HANDLE_INVOKE_T2(COMMAND, func) \ if(!is_notify && COMMAND::ID == command) \ - {handled=true;return epee::net_utils::buff_to_t_adapter(command, in_buff, buff_out, boost::bind(func, this, _1, _2, _3, _4), context);} + {handled=true;return epee::net_utils::buff_to_t_adapter(command, in_buff, buff_out, boost::bind(func, this, boost::placeholders::_1, boost::placeholders::_2, boost::placeholders::_3, boost::placeholders::_4), context);} #define HANDLE_NOTIFY2(command_id, func, type_name_in) \ if(is_notify && command_id == command) \ - {handled=true;return epee::net_utils::buff_to_t_adapter(this, command, in_buff, boost::bind(func, this, _1, _2, _3), context);} + {handled=true;return epee::net_utils::buff_to_t_adapter(this, command, in_buff, boost::bind(func, this, boost::placeholders::_1, boost::placeholders::_2, boost::placeholders::_3), context);} #define HANDLE_NOTIFY_T2(NOTIFY, func) \ if(is_notify && NOTIFY::ID == command) \ - {handled=true;return epee::net_utils::buff_to_t_adapter(this, command, in_buff, boost::bind(func, this, _1, _2, _3), context);} + {handled=true;return epee::net_utils::buff_to_t_adapter(this, command, in_buff, boost::bind(func, this, boost::placeholders::_1, boost::placeholders::_2, boost::placeholders::_3), context);} #define CHAIN_INVOKE_MAP2(func) \ diff --git a/src/common/ntp.cpp b/src/common/ntp.cpp index fdbc2a5b..b7f8a076 100644 --- a/src/common/ntp.cpp +++ b/src/common/ntp.cpp @@ -94,7 +94,7 @@ public: // Start the asynchronous operation itself. The handle_receive function // used as a callback will update the ec and length variables. socket_.async_receive(boost::asio::buffer(buffer), - boost::bind(&udp_blocking_client::handle_receive, _1, _2, &ec, &length)); + boost::bind(&udp_blocking_client::handle_receive, boost::placeholders::_1, boost::placeholders::_2, &ec, &length)); // Block until the asynchronous operation has completed. do io_service_.run_one(); while (ec == boost::asio::error::would_block); diff --git a/src/daemon/daemon_commands_handler.h b/src/daemon/daemon_commands_handler.h index 4573b806..78d2ffef 100644 --- a/src/daemon/daemon_commands_handler.h +++ b/src/daemon/daemon_commands_handler.h @@ -7,6 +7,7 @@ #pragma once #include +#include #include "console_handler.h" #include "p2p/net_node.h" @@ -18,6 +19,8 @@ #include "serialization/binary_utils.h" #include "simplewallet/password_container.h" +namespace ph = boost::placeholders; + PUSH_VS_WARNINGS DISABLE_VS_WARNINGS(4100) @@ -31,49 +34,49 @@ class daemon_commands_handler public: daemon_commands_handler(nodetool::node_server >& srv, currency::core_rpc_server& rpc) :m_srv(srv), m_rpc(rpc) { - m_cmd_binder.set_handler("help", boost::bind(&console_handlers_binder::help, &m_cmd_binder, _1), "Show this help"); - m_cmd_binder.set_handler("print_pl", boost::bind(&daemon_commands_handler::print_pl, this, _1), "Print peer list"); - m_cmd_binder.set_handler("print_cn", boost::bind(&daemon_commands_handler::print_cn, this, _1), "Print connections"); - m_cmd_binder.set_handler("print_bc", boost::bind(&daemon_commands_handler::print_bc, this, _1), "Print blockchain info in a given blocks range, print_bc []"); - m_cmd_binder.set_handler("print_bc_tx", boost::bind(&daemon_commands_handler::print_bc_tx, this, _1), "Print blockchain info with trnsactions in a given blocks range, print_bc []"); - //m_cmd_binder.set_handler("print_bci", boost::bind(&daemon_commands_handler::print_bci, this, _1)); - m_cmd_binder.set_handler("print_bc_outs", boost::bind(&daemon_commands_handler::print_bc_outs, this, _1)); - m_cmd_binder.set_handler("print_market", boost::bind(&daemon_commands_handler::print_market, this, _1)); - m_cmd_binder.set_handler("print_bc_outs_stats", boost::bind(&daemon_commands_handler::print_bc_outs_stats, this, _1)); - m_cmd_binder.set_handler("print_block", boost::bind(&daemon_commands_handler::print_block, this, _1), "Print block, print_block | "); - m_cmd_binder.set_handler("print_block_info", boost::bind(&daemon_commands_handler::print_block_info, this, _1), "Print block info, print_block | "); - m_cmd_binder.set_handler("print_tx_prun_info", boost::bind(&daemon_commands_handler::print_tx_prun_info, this, _1), "Print tx prunning info"); - m_cmd_binder.set_handler("print_tx", boost::bind(&daemon_commands_handler::print_tx, this, _1), "Print transaction, print_tx "); - m_cmd_binder.set_handler("start_mining", boost::bind(&daemon_commands_handler::start_mining, this, _1), "Start mining for specified address, start_mining [threads=1]"); - m_cmd_binder.set_handler("stop_mining", boost::bind(&daemon_commands_handler::stop_mining, this, _1), "Stop mining"); - m_cmd_binder.set_handler("print_pool", boost::bind(&daemon_commands_handler::print_pool, this, _1), "Print transaction pool (long format)"); - m_cmd_binder.set_handler("print_pool_sh", boost::bind(&daemon_commands_handler::print_pool_sh, this, _1), "Print transaction pool (short format)"); - m_cmd_binder.set_handler("show_hr", boost::bind(&daemon_commands_handler::show_hr, this, _1), "Start showing hash rate"); - m_cmd_binder.set_handler("hide_hr", boost::bind(&daemon_commands_handler::hide_hr, this, _1), "Stop showing hash rate"); - m_cmd_binder.set_handler("save", boost::bind(&daemon_commands_handler::save, this, _1), "Save blockchain"); - m_cmd_binder.set_handler("print_daemon_stat", boost::bind(&daemon_commands_handler::print_daemon_stat, this, _1), "Print daemon stat"); - m_cmd_binder.set_handler("print_debug_stat", boost::bind(&daemon_commands_handler::print_debug_stat, this, _1), "Print debug stat info"); - m_cmd_binder.set_handler("get_transactions_statics", boost::bind(&daemon_commands_handler::get_transactions_statistics, this, _1), "Calculates transactions statistics"); - m_cmd_binder.set_handler("force_relay_tx_pool", boost::bind(&daemon_commands_handler::force_relay_tx_pool, this, _1), "re-relay all transactions from pool"); - m_cmd_binder.set_handler("enable_channel", boost::bind(&daemon_commands_handler::enable_channel, this, _1), "Enable specified log channel"); - m_cmd_binder.set_handler("disable_channel", boost::bind(&daemon_commands_handler::disable_channel, this, _1), "Enable specified log channel"); - m_cmd_binder.set_handler("clear_cache", boost::bind(&daemon_commands_handler::clear_cache, this, _1), "Clear blockchain storage cache"); - m_cmd_binder.set_handler("clear_altblocks", boost::bind(&daemon_commands_handler::clear_altblocks, this, _1), "Clear blockchain storage cache"); - m_cmd_binder.set_handler("truncate_bc", boost::bind(&daemon_commands_handler::truncate_bc, this, _1), "Truncate blockchain to specified height"); - m_cmd_binder.set_handler("inspect_block_index", boost::bind(&daemon_commands_handler::inspect_block_index, this, _1), "Inspects block index for internal errors"); - m_cmd_binder.set_handler("print_db_performance_data", boost::bind(&daemon_commands_handler::print_db_performance_data, this, _1), "Dumps all db containers performance counters"); - m_cmd_binder.set_handler("search_by_id", boost::bind(&daemon_commands_handler::search_by_id, this, _1), "Search all possible elemets by given id"); - m_cmd_binder.set_handler("find_key_image", boost::bind(&daemon_commands_handler::find_key_image, this, _1), "Try to find tx related to key_image"); - m_cmd_binder.set_handler("rescan_aliases", boost::bind(&daemon_commands_handler::rescan_aliases, this, _1), "Debug function"); - m_cmd_binder.set_handler("forecast_difficulty", boost::bind(&daemon_commands_handler::forecast_difficulty, this, _1), "Prints PoW and PoS difficulties for as many future blocks as possible based on current conditions"); - m_cmd_binder.set_handler("print_deadlock_guard", boost::bind(&daemon_commands_handler::print_deadlock_guard, this, _1), "Print all threads which is blocked or involved in mutex ownership"); - m_cmd_binder.set_handler("print_block_from_hex_blob", boost::bind(&daemon_commands_handler::print_block_from_hex_blob, this, _1), "Unserialize block from hex binary data to json-like representation"); - m_cmd_binder.set_handler("print_tx_from_hex_blob", boost::bind(&daemon_commands_handler::print_tx_from_hex_blob, this, _1), "Unserialize transaction from hex binary data to json-like representation"); - m_cmd_binder.set_handler("print_tx_outputs_usage", boost::bind(&daemon_commands_handler::print_tx_outputs_usage, this, _1), "Analyse if tx outputs for involved in subsequent transactions"); - m_cmd_binder.set_handler("print_difficulties_of_last_n_blocks", boost::bind(&daemon_commands_handler::print_difficulties_of_last_n_blocks, this, _1), "Print difficulties of last n blocks"); - m_cmd_binder.set_handler("debug_remote_node_mode", boost::bind(&daemon_commands_handler::debug_remote_node_mode, this, _1), " - If node got connected put node into 'debug mode' i.e. no sync process of other communication except ping responses, maintenance secrete key will be requested"); + m_cmd_binder.set_handler("help", boost::bind(&console_handlers_binder::help, &m_cmd_binder, ph::_1), "Show this help"); + m_cmd_binder.set_handler("print_pl", boost::bind(&daemon_commands_handler::print_pl, this, ph::_1), "Print peer list"); + m_cmd_binder.set_handler("print_cn", boost::bind(&daemon_commands_handler::print_cn, this, ph::_1), "Print connections"); + m_cmd_binder.set_handler("print_bc", boost::bind(&daemon_commands_handler::print_bc, this, ph::_1), "Print blockchain info in a given blocks range, print_bc []"); + m_cmd_binder.set_handler("print_bc_tx", boost::bind(&daemon_commands_handler::print_bc_tx, this, ph::_1), "Print blockchain info with trnsactions in a given blocks range, print_bc []"); + //m_cmd_binder.set_handler("print_bci", boost::bind(&daemon_commands_handler::print_bci, this, ph::_1)); + m_cmd_binder.set_handler("print_bc_outs", boost::bind(&daemon_commands_handler::print_bc_outs, this, ph::_1)); + m_cmd_binder.set_handler("print_market", boost::bind(&daemon_commands_handler::print_market, this, ph::_1)); + m_cmd_binder.set_handler("print_bc_outs_stats", boost::bind(&daemon_commands_handler::print_bc_outs_stats, this, ph::_1)); + m_cmd_binder.set_handler("print_block", boost::bind(&daemon_commands_handler::print_block, this, ph::_1), "Print block, print_block | "); + m_cmd_binder.set_handler("print_block_info", boost::bind(&daemon_commands_handler::print_block_info, this, ph::_1), "Print block info, print_block | "); + m_cmd_binder.set_handler("print_tx_prun_info", boost::bind(&daemon_commands_handler::print_tx_prun_info, this, ph::_1), "Print tx prunning info"); + m_cmd_binder.set_handler("print_tx", boost::bind(&daemon_commands_handler::print_tx, this, ph::_1), "Print transaction, print_tx "); + m_cmd_binder.set_handler("start_mining", boost::bind(&daemon_commands_handler::start_mining, this, ph::_1), "Start mining for specified address, start_mining [threads=1]"); + m_cmd_binder.set_handler("stop_mining", boost::bind(&daemon_commands_handler::stop_mining, this, ph::_1), "Stop mining"); + m_cmd_binder.set_handler("print_pool", boost::bind(&daemon_commands_handler::print_pool, this, ph::_1), "Print transaction pool (long format)"); + m_cmd_binder.set_handler("print_pool_sh", boost::bind(&daemon_commands_handler::print_pool_sh, this, ph::_1), "Print transaction pool (short format)"); + m_cmd_binder.set_handler("show_hr", boost::bind(&daemon_commands_handler::show_hr, this, ph::_1), "Start showing hash rate"); + m_cmd_binder.set_handler("hide_hr", boost::bind(&daemon_commands_handler::hide_hr, this, ph::_1), "Stop showing hash rate"); + m_cmd_binder.set_handler("save", boost::bind(&daemon_commands_handler::save, this, ph::_1), "Save blockchain"); + m_cmd_binder.set_handler("print_daemon_stat", boost::bind(&daemon_commands_handler::print_daemon_stat, this, ph::_1), "Print daemon stat"); + m_cmd_binder.set_handler("print_debug_stat", boost::bind(&daemon_commands_handler::print_debug_stat, this, ph::_1), "Print debug stat info"); + m_cmd_binder.set_handler("get_transactions_statics", boost::bind(&daemon_commands_handler::get_transactions_statistics, this, ph::_1), "Calculates transactions statistics"); + m_cmd_binder.set_handler("force_relay_tx_pool", boost::bind(&daemon_commands_handler::force_relay_tx_pool, this, ph::_1), "re-relay all transactions from pool"); + m_cmd_binder.set_handler("enable_channel", boost::bind(&daemon_commands_handler::enable_channel, this, ph::_1), "Enable specified log channel"); + m_cmd_binder.set_handler("disable_channel", boost::bind(&daemon_commands_handler::disable_channel, this, ph::_1), "Enable specified log channel"); + m_cmd_binder.set_handler("clear_cache", boost::bind(&daemon_commands_handler::clear_cache, this, ph::_1), "Clear blockchain storage cache"); + m_cmd_binder.set_handler("clear_altblocks", boost::bind(&daemon_commands_handler::clear_altblocks, this, ph::_1), "Clear blockchain storage cache"); + m_cmd_binder.set_handler("truncate_bc", boost::bind(&daemon_commands_handler::truncate_bc, this, ph::_1), "Truncate blockchain to specified height"); + m_cmd_binder.set_handler("inspect_block_index", boost::bind(&daemon_commands_handler::inspect_block_index, this, ph::_1), "Inspects block index for internal errors"); + m_cmd_binder.set_handler("print_db_performance_data", boost::bind(&daemon_commands_handler::print_db_performance_data, this, ph::_1), "Dumps all db containers performance counters"); + m_cmd_binder.set_handler("search_by_id", boost::bind(&daemon_commands_handler::search_by_id, this, ph::_1), "Search all possible elemets by given id"); + m_cmd_binder.set_handler("find_key_image", boost::bind(&daemon_commands_handler::find_key_image, this, ph::_1), "Try to find tx related to key_image"); + m_cmd_binder.set_handler("rescan_aliases", boost::bind(&daemon_commands_handler::rescan_aliases, this, ph::_1), "Debug function"); + m_cmd_binder.set_handler("forecast_difficulty", boost::bind(&daemon_commands_handler::forecast_difficulty, this, ph::_1), "Prints PoW and PoS difficulties for as many future blocks as possible based on current conditions"); + m_cmd_binder.set_handler("print_deadlock_guard", boost::bind(&daemon_commands_handler::print_deadlock_guard, this, ph::_1), "Print all threads which is blocked or involved in mutex ownership"); + m_cmd_binder.set_handler("print_block_from_hex_blob", boost::bind(&daemon_commands_handler::print_block_from_hex_blob, this, ph::_1), "Unserialize block from hex binary data to json-like representation"); + m_cmd_binder.set_handler("print_tx_from_hex_blob", boost::bind(&daemon_commands_handler::print_tx_from_hex_blob, this, ph::_1), "Unserialize transaction from hex binary data to json-like representation"); + m_cmd_binder.set_handler("print_tx_outputs_usage", boost::bind(&daemon_commands_handler::print_tx_outputs_usage, this, ph::_1), "Analyse if tx outputs for involved in subsequent transactions"); + m_cmd_binder.set_handler("print_difficulties_of_last_n_blocks", boost::bind(&daemon_commands_handler::print_difficulties_of_last_n_blocks, this, ph::_1), "Print difficulties of last n blocks"); + m_cmd_binder.set_handler("debug_remote_node_mode", boost::bind(&daemon_commands_handler::debug_remote_node_mode, this, ph::_1), " - If node got connected put node into 'debug mode' i.e. no sync process of other communication except ping responses, maintenance secrete key will be requested"); #ifdef _DEBUG - m_cmd_binder.set_handler("debug_set_time_adj", boost::bind(&daemon_commands_handler::debug_set_time_adj, this, _1), "DEBUG: set core time adjustment"); + m_cmd_binder.set_handler("debug_set_time_adj", boost::bind(&daemon_commands_handler::debug_set_time_adj, this, ph::_1), "DEBUG: set core time adjustment"); #endif } diff --git a/src/simplewallet/simplewallet.cpp b/src/simplewallet/simplewallet.cpp index cfb48a64..fe277c72 100644 --- a/src/simplewallet/simplewallet.cpp +++ b/src/simplewallet/simplewallet.cpp @@ -33,6 +33,7 @@ using namespace epee; using namespace currency; using boost::lexical_cast; namespace po = boost::program_options; +namespace ph = boost::placeholders; #define EXTENDED_LOGS_FILE "wallet_details.log" @@ -186,49 +187,49 @@ simple_wallet::simple_wallet() m_refresh_progress_reporter(*this), m_offline_mode(false) { - m_cmd_binder.set_handler("start_mining", boost::bind(&simple_wallet::start_mining, this, _1), "start_mining - Start mining in daemon"); - m_cmd_binder.set_handler("stop_mining", boost::bind(&simple_wallet::stop_mining, this, _1), "Stop mining in daemon"); - m_cmd_binder.set_handler("refresh", boost::bind(&simple_wallet::refresh, this, _1), "Resynchronize transactions and balance"); - m_cmd_binder.set_handler("balance", boost::bind(&simple_wallet::show_balance, this, _1), "Show current wallet balance"); - m_cmd_binder.set_handler("incoming_transfers", boost::bind(&simple_wallet::show_incoming_transfers, this, _1), "incoming_transfers [available|unavailable] - Show incoming transfers - all of them or filter them by availability"); - m_cmd_binder.set_handler("incoming_counts", boost::bind(&simple_wallet::show_incoming_transfers_counts, this, _1), "incoming_transfers counts"); - m_cmd_binder.set_handler("list_recent_transfers", boost::bind(&simple_wallet::list_recent_transfers, this, _1), "list_recent_transfers [offset] [count] - Show recent maximum 1000 transfers, offset default = 0, count default = 100 "); - m_cmd_binder.set_handler("export_recent_transfers", boost::bind(&simple_wallet::export_recent_transfers, this, _1), "list_recent_transfers_tx - Write recent transfer in json to wallet_recent_transfers.txt"); - m_cmd_binder.set_handler("list_outputs", boost::bind(&simple_wallet::list_outputs, this, _1), "list_outputs [spent|unspent] - Lists all the outputs that have ever been sent to this wallet if called without arguments, otherwise it lists only the spent or unspent outputs"); - m_cmd_binder.set_handler("dump_transfers", boost::bind(&simple_wallet::dump_trunsfers, this, _1), "dump_transfers - Write transfers in json to dump_transfers.txt"); - m_cmd_binder.set_handler("dump_keyimages", boost::bind(&simple_wallet::dump_key_images, this, _1), "dump_keyimages - Write key_images in json to dump_key_images.txt"); - m_cmd_binder.set_handler("payments", boost::bind(&simple_wallet::show_payments, this, _1), "payments [ ... ] - Show payments , ... "); - m_cmd_binder.set_handler("bc_height", boost::bind(&simple_wallet::show_blockchain_height, this, _1), "Show blockchain height"); - m_cmd_binder.set_handler("wallet_bc_height", boost::bind(&simple_wallet::show_wallet_bcheight, this, _1), "Show blockchain height"); - m_cmd_binder.set_handler("transfer", boost::bind(&simple_wallet::transfer, this, _1), "transfer [ ... ] [payment_id] - Transfer ,... to ,... , respectively. is the number of transactions yours is indistinguishable from (from 0 to maximum available), is an optional HEX-encoded string"); - m_cmd_binder.set_handler("set_log", boost::bind(&simple_wallet::set_log, this, _1), "set_log - Change current log detalisation level, is a number 0-4"); - m_cmd_binder.set_handler("enable_console_logger", boost::bind(&simple_wallet::enable_console_logger, this, _1), "Enables console logging"); - m_cmd_binder.set_handler("resync", boost::bind(&simple_wallet::resync_wallet, this, _1), "Causes wallet to reset all transfers and re-synchronize wallet"); - m_cmd_binder.set_handler("help", boost::bind(&simple_wallet::help, this, _1), "Show this help"); - m_cmd_binder.set_handler("get_transfer_info", boost::bind(&simple_wallet::get_transfer_info, this, _1), "displays transfer info by key_image or index"); - m_cmd_binder.set_handler("scan_for_collision", boost::bind(&simple_wallet::scan_for_key_image_collisions, this, _1), "Rescan transfers for key image collisions"); - m_cmd_binder.set_handler("fix_collisions", boost::bind(&simple_wallet::fix_collisions, this, _1), "Rescan transfers for key image collisions"); - m_cmd_binder.set_handler("scan_transfers_for_id", boost::bind(&simple_wallet::scan_transfers_for_id, this, _1), "Rescan transfers for tx_id"); - m_cmd_binder.set_handler("scan_transfers_for_ki", boost::bind(&simple_wallet::scan_transfers_for_ki, this, _1), "Rescan transfers for key image"); - m_cmd_binder.set_handler("print_utxo_distribution", boost::bind(&simple_wallet::print_utxo_distribution, this, _1), "Prints utxo distribution"); - m_cmd_binder.set_handler("sweep_below", boost::bind(&simple_wallet::sweep_below, this, _1), "sweep_below
[payment_id] - Tries to transfers all coins with amount below the given limit to the given address"); + m_cmd_binder.set_handler("start_mining", boost::bind(&simple_wallet::start_mining, this, ph::_1), "start_mining - Start mining in daemon"); + m_cmd_binder.set_handler("stop_mining", boost::bind(&simple_wallet::stop_mining, this, ph::_1), "Stop mining in daemon"); + m_cmd_binder.set_handler("refresh", boost::bind(&simple_wallet::refresh, this, ph::_1), "Resynchronize transactions and balance"); + m_cmd_binder.set_handler("balance", boost::bind(&simple_wallet::show_balance, this, ph::_1), "Show current wallet balance"); + m_cmd_binder.set_handler("incoming_transfers", boost::bind(&simple_wallet::show_incoming_transfers, this, ph::_1), "incoming_transfers [available|unavailable] - Show incoming transfers - all of them or filter them by availability"); + m_cmd_binder.set_handler("incoming_counts", boost::bind(&simple_wallet::show_incoming_transfers_counts, this, ph::_1), "incoming_transfers counts"); + m_cmd_binder.set_handler("list_recent_transfers", boost::bind(&simple_wallet::list_recent_transfers, this, ph::_1), "list_recent_transfers [offset] [count] - Show recent maximum 1000 transfers, offset default = 0, count default = 100 "); + m_cmd_binder.set_handler("export_recent_transfers", boost::bind(&simple_wallet::export_recent_transfers, this, ph::_1), "list_recent_transfers_tx - Write recent transfer in json to wallet_recent_transfers.txt"); + m_cmd_binder.set_handler("list_outputs", boost::bind(&simple_wallet::list_outputs, this, ph::_1), "list_outputs [spent|unspent] - Lists all the outputs that have ever been sent to this wallet if called without arguments, otherwise it lists only the spent or unspent outputs"); + m_cmd_binder.set_handler("dump_transfers", boost::bind(&simple_wallet::dump_trunsfers, this, ph::_1), "dump_transfers - Write transfers in json to dump_transfers.txt"); + m_cmd_binder.set_handler("dump_keyimages", boost::bind(&simple_wallet::dump_key_images, this, ph::_1), "dump_keyimages - Write key_images in json to dump_key_images.txt"); + m_cmd_binder.set_handler("payments", boost::bind(&simple_wallet::show_payments, this, ph::_1), "payments [ ... ] - Show payments , ... "); + m_cmd_binder.set_handler("bc_height", boost::bind(&simple_wallet::show_blockchain_height, this,ph::_1), "Show blockchain height"); + m_cmd_binder.set_handler("wallet_bc_height", boost::bind(&simple_wallet::show_wallet_bcheight, this,ph::_1), "Show blockchain height"); + m_cmd_binder.set_handler("transfer", boost::bind(&simple_wallet::transfer, this,ph::_1), "transfer [ ... ] [payment_id] - Transfer ,... to ,... , respectively. is the number of transactions yours is indistinguishable from (from 0 to maximum available), is an optional HEX-encoded string"); + m_cmd_binder.set_handler("set_log", boost::bind(&simple_wallet::set_log, this,ph::_1), "set_log - Change current log detalisation level, is a number 0-4"); + m_cmd_binder.set_handler("enable_console_logger", boost::bind(&simple_wallet::enable_console_logger, this,ph::_1), "Enables console logging"); + m_cmd_binder.set_handler("resync", boost::bind(&simple_wallet::resync_wallet, this,ph::_1), "Causes wallet to reset all transfers and re-synchronize wallet"); + m_cmd_binder.set_handler("help", boost::bind(&simple_wallet::help, this,ph::_1), "Show this help"); + m_cmd_binder.set_handler("get_transfer_info", boost::bind(&simple_wallet::get_transfer_info, this,ph::_1), "displays transfer info by key_image or index"); + m_cmd_binder.set_handler("scan_for_collision", boost::bind(&simple_wallet::scan_for_key_image_collisions, this,ph::_1), "Rescan transfers for key image collisions"); + m_cmd_binder.set_handler("fix_collisions", boost::bind(&simple_wallet::fix_collisions, this,ph::_1), "Rescan transfers for key image collisions"); + m_cmd_binder.set_handler("scan_transfers_for_id", boost::bind(&simple_wallet::scan_transfers_for_id, this,ph::_1), "Rescan transfers for tx_id"); + m_cmd_binder.set_handler("scan_transfers_for_ki", boost::bind(&simple_wallet::scan_transfers_for_ki, this,ph::_1), "Rescan transfers for key image"); + m_cmd_binder.set_handler("print_utxo_distribution", boost::bind(&simple_wallet::print_utxo_distribution, this,ph::_1), "Prints utxo distribution"); + m_cmd_binder.set_handler("sweep_below", boost::bind(&simple_wallet::sweep_below, this,ph::_1), "sweep_below
[payment_id] - Tries to transfers all coins with amount below the given limit to the given address"); - m_cmd_binder.set_handler("address", boost::bind(&simple_wallet::print_address, this, _1), "Show current wallet public address"); - m_cmd_binder.set_handler("integrated_address", boost::bind(&simple_wallet::integrated_address, this, _1), "integrated_address [||"); + m_cmd_binder.set_handler("get_tx_key", boost::bind(&simple_wallet::get_tx_key, this,ph::_1), "Get transaction one-time secret key (r) for a given "); - m_cmd_binder.set_handler("tracking_seed", boost::bind(&simple_wallet::tracking_seed, this, _1), "For auditable wallets: prints tracking seed for wallet's audit by a third party"); + m_cmd_binder.set_handler("tracking_seed", boost::bind(&simple_wallet::tracking_seed, this,ph::_1), "For auditable wallets: prints tracking seed for wallet's audit by a third party"); - m_cmd_binder.set_handler("save", boost::bind(&simple_wallet::save, this, _1), "Save wallet synchronized data"); - m_cmd_binder.set_handler("save_watch_only", boost::bind(&simple_wallet::save_watch_only, this, _1), "save_watch_only - save as watch-only wallet file."); + m_cmd_binder.set_handler("save", boost::bind(&simple_wallet::save, this,ph::_1), "Save wallet synchronized data"); + m_cmd_binder.set_handler("save_watch_only", boost::bind(&simple_wallet::save_watch_only, this,ph::_1), "save_watch_only - save as watch-only wallet file."); - m_cmd_binder.set_handler("sign_transfer", boost::bind(&simple_wallet::sign_transfer, this, _1), "sign_transfer - sign unsigned tx from a watch-only wallet"); - m_cmd_binder.set_handler("submit_transfer", boost::bind(&simple_wallet::submit_transfer, this, _1), "submit_transfer - broadcast signed tx"); - m_cmd_binder.set_handler("export_history", boost::bind(&simple_wallet::submit_transfer, this, _1), "Export transaction history in CSV file"); + m_cmd_binder.set_handler("sign_transfer", boost::bind(&simple_wallet::sign_transfer, this,ph::_1), "sign_transfer - sign unsigned tx from a watch-only wallet"); + m_cmd_binder.set_handler("submit_transfer", boost::bind(&simple_wallet::submit_transfer, this,ph::_1), "submit_transfer - broadcast signed tx"); + m_cmd_binder.set_handler("export_history", boost::bind(&simple_wallet::submit_transfer, this,ph::_1), "Export transaction history in CSV file"); } //---------------------------------------------------------------------------------------------------- simple_wallet::~simple_wallet() From 2246aa8fcec48146d9a9e51f374df69d65d47608 Mon Sep 17 00:00:00 2001 From: sowle Date: Mon, 21 Mar 2022 01:20:56 +0300 Subject: [PATCH 04/15] fix an issue with boost 1.76 --- .../include/serialization/keyvalue_serialization_overloads.h | 1 + 1 file changed, 1 insertion(+) diff --git a/contrib/epee/include/serialization/keyvalue_serialization_overloads.h b/contrib/epee/include/serialization/keyvalue_serialization_overloads.h index 01f9e257..d33d5ad1 100644 --- a/contrib/epee/include/serialization/keyvalue_serialization_overloads.h +++ b/contrib/epee/include/serialization/keyvalue_serialization_overloads.h @@ -27,6 +27,7 @@ #pragma once #include +#include #include namespace epee From 2478dbb677c23d2a8cad404d3c38c0b01497f531 Mon Sep 17 00:00:00 2001 From: sowle Date: Mon, 21 Mar 2022 19:45:21 +0300 Subject: [PATCH 05/15] coretests fixed --- tests/core_tests/chaingen_main.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/core_tests/chaingen_main.cpp b/tests/core_tests/chaingen_main.cpp index 3e9cbc80..0765a006 100644 --- a/tests/core_tests/chaingen_main.cpp +++ b/tests/core_tests/chaingen_main.cpp @@ -667,6 +667,7 @@ int main(int argc, char* argv[]) command_line::add_arg(desc_options, arg_enable_debug_asserts); command_line::add_arg(desc_options, command_line::arg_data_dir, std::string(".")); command_line::add_arg(desc_options, command_line::arg_stop_after_height); + command_line::add_arg(desc_options, command_line::arg_disable_ntp); currency::core::init_options(desc_options); tools::db::db_backend_selector::init_options(desc_options); From b9ccb10287dd21433ece375ced5b4f3d910a9f50 Mon Sep 17 00:00:00 2001 From: sowle Date: Sat, 9 Apr 2022 21:12:44 +0200 Subject: [PATCH 06/15] crypto: scalar_t::git_bit + test crypto_sc_get_bit; hash_helper_t extended with hp variants --- src/crypto/crypto-sugar.h | 22 ++++++++++++++ tests/functional_tests/crypto_tests.cpp | 40 +++++++++++++++++++++++++ 2 files changed, 62 insertions(+) diff --git a/src/crypto/crypto-sugar.h b/src/crypto/crypto-sugar.h index 5542b9fb..e5ce7b9b 100644 --- a/src/crypto/crypto-sugar.h +++ b/src/crypto/crypto-sugar.h @@ -431,6 +431,13 @@ namespace crypto return result; } + bool get_bit(size_t bit_index) const + { + if (bit_index > 255) + return false; // TODO: consider performace implications + return (m_u64[bit_index >> 6] & (1ull << (bit_index & 63))) != 0; + } + }; // struct scalar_t // @@ -1063,6 +1070,21 @@ namespace crypto ge_bytes_hash_to_ec_32(&result.m_p3, (const unsigned char*)&p); return result; } + + static point_t hp(const scalar_t& s) + { + point_t result; + ge_bytes_hash_to_ec_32(&result.m_p3, s.data()); + return result; + } + + static point_t hp(const void* data, size_t size) + { + point_t result; + ge_bytes_hash_to_ec(&result.m_p3, data, size); + return result; + } + }; // hash_helper_t struct diff --git a/tests/functional_tests/crypto_tests.cpp b/tests/functional_tests/crypto_tests.cpp index 83c94b8b..19c922e2 100644 --- a/tests/functional_tests/crypto_tests.cpp +++ b/tests/functional_tests/crypto_tests.cpp @@ -1803,6 +1803,46 @@ TEST(crypto, point_is_zero) } +TEST(crypto, sc_get_bit) +{ + static_assert(sizeof(scalar_t) * 8 == 256, "size missmatch"); + + scalar_t v = 0; // all bits are 0 + for (size_t n = 0; n < 256; ++n) + { + ASSERT_EQ(v.get_bit(n), false); + } + + v = c_scalar_256m1; // all bits are 1 + for (size_t n = 0; n < 256; ++n) + { + ASSERT_EQ(v.get_bit(n), true); + } + + // bits out of the [0; 255] range supposed to be always 0 + for (size_t n = 256; n < 2048; ++n) + { + ASSERT_EQ(v.get_bit(n), false); + } + + // check random value + const scalar_t x = scalar_t::random(); + for (size_t n = 0; n < 64; ++n) + ASSERT_EQ(x.get_bit(n), ((x.m_u64[0] & (1ull << (n - 0))) != 0)); + for (size_t n = 64; n < 128; ++n) + ASSERT_EQ(x.get_bit(n), ((x.m_u64[1] & (1ull << (n - 64))) != 0)); + for (size_t n = 128; n < 192; ++n) + ASSERT_EQ(x.get_bit(n), ((x.m_u64[2] & (1ull << (n - 128))) != 0)); + for (size_t n = 192; n < 256; ++n) + ASSERT_EQ(x.get_bit(n), ((x.m_u64[3] & (1ull << (n - 192))) != 0)); + + // bits out of the [0; 255] range supposed to be always 0 + for (size_t n = 256; n < 2048; ++n) + ASSERT_EQ(x.get_bit(n), false); + + return true; +} + // // test's runner // From 319d53f7cf09331f257b525eaa399482124520b1 Mon Sep 17 00:00:00 2001 From: sowle Date: Sun, 10 Apr 2022 19:45:45 +0200 Subject: [PATCH 07/15] crypto: H2 introduced, functional tests main's clean-up --- src/crypto/crypto-sugar.cpp | 1 + src/crypto/crypto-sugar.h | 1 + tests/functional_tests/main.cpp | 3 --- 3 files changed, 2 insertions(+), 3 deletions(-) diff --git a/src/crypto/crypto-sugar.cpp b/src/crypto/crypto-sugar.cpp index 4774e9b7..8b8779ae 100644 --- a/src/crypto/crypto-sugar.cpp +++ b/src/crypto/crypto-sugar.cpp @@ -21,6 +21,7 @@ namespace crypto const scalar_t c_scalar_1div8 = { 0x6106e529e2dc2f79, 0x07d39db37d1cdad0, 0x0, 0x0600000000000000 }; const point_t c_point_H = { 0x05087c1f5b9b32d6, 0x00547595f445c3b5, 0x764df64578552f2a, 0x8a49a651e0e0da45 }; // == Hp(G), this is being checked in bpp_basics + const point_t c_point_H2 = { 0x70c8d1ab9dbf1cc0, 0xc561bb12639a8516, 0x3cfff1def9e5b268, 0xe0936386f3bcce1a }; // == Hp("h2_generator"), cheched in bpp_basics const point_t c_point_0 = point_t(point_t::tag_zero()); } // namespace crypto diff --git a/src/crypto/crypto-sugar.h b/src/crypto/crypto-sugar.h index e5ce7b9b..d1928a92 100644 --- a/src/crypto/crypto-sugar.h +++ b/src/crypto/crypto-sugar.h @@ -897,6 +897,7 @@ namespace crypto extern const point_g_t c_point_G; extern const point_t c_point_H; + extern const point_t c_point_H2; extern const point_t c_point_0; // diff --git a/tests/functional_tests/main.cpp b/tests/functional_tests/main.cpp index ed53cbe3..fc3da2d0 100644 --- a/tests/functional_tests/main.cpp +++ b/tests/functional_tests/main.cpp @@ -66,9 +66,6 @@ int main(int argc, char* argv[]) TRY_ENTRY(); string_tools::set_module_name_and_folder(argv[0]); - uint64_t reward = 0; - currency::get_block_reward(false, 500000, 589313, 10300000000000000, reward, 11030); - //set up logging options //log_space::get_set_log_detalisation_level(true, LOG_LEVEL_1); //log_space::log_singletone::add_logger(LOGGER_CONSOLE, NULL, NULL, LOG_LEVEL_2); From 10141c3dfca4bd1c354e6ff24bad4813430d0252 Mon Sep 17 00:00:00 2001 From: sowle Date: Sun, 10 Apr 2022 19:50:13 +0200 Subject: [PATCH 08/15] crypto: range proofs major refactoring, crypto traits refactored, calc_exp_power_of_2_upper_bound changed to constexpr analogs --- src/crypto/range_proof_bpp.h | 698 ++++++++++++++++ src/crypto/range_proofs.cpp | 3 - src/crypto/range_proofs.h | 751 +----------------- tests/functional_tests/crypto_tests.cpp | 2 + .../crypto_tests_range_proofs.h | 182 +++++ 5 files changed, 921 insertions(+), 715 deletions(-) create mode 100644 src/crypto/range_proof_bpp.h create mode 100644 tests/functional_tests/crypto_tests_range_proofs.h diff --git a/src/crypto/range_proof_bpp.h b/src/crypto/range_proof_bpp.h new file mode 100644 index 00000000..a8b68807 --- /dev/null +++ b/src/crypto/range_proof_bpp.h @@ -0,0 +1,698 @@ +// Copyright (c) 2021-2022 Zano Project (https://zano.org/) +// Copyright (c) 2021-2022 sowle (val@zano.org, crypto.sowle@gmail.com) +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. +#pragma once + +// +// This file contains the implementation of range proof protocol. +// Namely, Bulletproofs+ https://eprint.iacr.org/2020/735 +// + +namespace crypto +{ + struct bpp_signature + { + std::vector L; // size = ceil( log_2(m * n) ) + std::vector R; + public_key A0; + public_key A; + public_key B; + scalar_t r; + scalar_t s; + scalar_t delta; + }; + +#define DBG_VAL_PRINT(x) std::cout << #x ": " << x << ENDL +#define DBG_PRINT(x) std::cout << x << ENDL + + template + bool bpp_gen(const scalar_vec_t& values, const scalar_vec_t& masks, bpp_signature& sig, std::vector& commitments, uint8_t* p_err = nullptr) + { +#define CHECK_AND_FAIL_WITH_ERROR_IF_FALSE(cond, err_code) \ + if (!(cond)) { LOG_PRINT_RED("bpp_gen: \"" << #cond << "\" is false at " << LOCATION_SS << ENDL << "error code = " << err_code, LOG_LEVEL_3); \ + if (p_err) { *p_err = err_code; } return false; } + + CHECK_AND_FAIL_WITH_ERROR_IF_FALSE(values.size() > 0 && values.size() <= CT::c_bpp_values_max && values.size() == masks.size(), 1); + CHECK_AND_FAIL_WITH_ERROR_IF_FALSE(masks.is_reduced(), 3); + + const size_t c_bpp_log2_m = constexpr_ceil_log2(values.size()); + const size_t c_bpp_m = 1ull << c_bpp_log2_m; + const size_t c_bpp_mn = c_bpp_m * CT::c_bpp_n; + const size_t c_bpp_log2_mn = c_bpp_log2_m + CT::c_bpp_log2_n; + + // pre-multiply all output points by c_scalar_1div8 + // in order to enforce these points to be in the prime-order subgroup (after mul by 8 in bpp_verify()) + + // calc commitments vector as commitments[i] = 1/8 * values[i] * G + 1/8 * masks[i] * H + commitments.resize(values.size()); + for (size_t i = 0; i < values.size(); ++i) + CT::calc_pedersen_commitment(values[i] * c_scalar_1div8, masks[i] * c_scalar_1div8, commitments[i]); + + + // s.a. BP+ paper, page 15, eq. 11 + // decompose v into aL and aR: + // v = aL o (1, 2, 2^2, ..., 2^n-1), o - component-wise product aka Hadamard product + // aR = aL - (1, 1, ... 1) + // aR o aL = 0 + + // aLs = (aL_0, aL_1, ..., aL_m-1) -- `bit` matrix of c_bpp_m x c_bpp_n, each element is a scalar + + scalar_mat_t aLs(c_bpp_mn), aRs(c_bpp_mn); + aLs.zero(); + aRs.zero(); + // m >= values.size, first set up [0..values.size-1], then -- [values.size..m-1] (padding area) + for (size_t i = 0; i < values.size(); ++i) + { + const scalar_t& v = values[i]; + for (size_t j = 0; j < CT::c_bpp_n; ++j) + { + if (v.get_bit(j)) + aLs(i, j) = c_scalar_1; // aL = 1, aR = 0 + else + aRs(i, j) = c_scalar_Lm1; // aL = 0, aR = -1 + } + } + + for (size_t i = values.size(); i < c_bpp_m; ++i) + for (size_t j = 0; j < CT::c_bpp_n; ++j) + aRs(i, j) = c_scalar_Lm1; // aL = 0, aR = -1 + + + // using e as Fiat-Shamir transcript + scalar_t e = CT::get_initial_transcript(); + DBG_PRINT("initial transcript: " << e); + + hash_helper_t::hs_t hsc; + CT::update_transcript(hsc, e, commitments); + + // BP+ paper, page 15: The prover begins with sending A = g^aL h^aR h^alpha (group element) + // so we calculate A0 = alpha * H + SUM(aL_i * G_i) + SUM(aR_i * H_i) + + scalar_t alpha = scalar_t::random(); + point_t A0 = alpha * CT::bpp_H; + + for (size_t i = 0; i < c_bpp_mn; ++i) + A0 += aLs[i] * CT::get_generator(false, i) + aRs[i] * CT::get_generator(true, i); + + // part of 1/8 defense scheme + A0 *= c_scalar_1div8; + A0.to_public_key(sig.A0); + + DBG_VAL_PRINT(alpha); + DBG_VAL_PRINT(A0); + + // calculate scalar challenges y and z + hsc.add_scalar(e); + hsc.add_pub_key(sig.A0); + scalar_t y = hsc.calc_hash(); + scalar_t z = hash_helper_t::hs(y); + e = z; // transcript for further steps + DBG_VAL_PRINT(y); + DBG_VAL_PRINT(z); + + // Computing vector d for aggregated version of the protocol (BP+ paper, page 17) + // (note: elements is stored column-by-column in memory) + // d = | 1 * z^(2*1), 1 * z^(2*2), 1 * z^(2*3), ..., 1 * z^(2*m) | + // | 2 * z^(2*1), 2 * z^(2*2), 2 * z^(2*3), ..., 2 * z^(2*m) | + // | 4 * z^(2*1), 4 * z^(2*2), 4 * z^(2*3), ..., 4 * z^(2*m) | + // | ....................................................................................... | + // | 2^(n-1) * z^(2*1), 2^(n-1) * z^(2*2), 2^(n-1) * z^(2*3), ..., 2^(n-1) * z^(2*m)) | + // Note: sum(d_i) = (2^n - 1) * ((z^2)^1 + (z^2)^2 + ... (z^2)^m)) = (2^n-1) * sum_of_powers(x^2, log(m)) + + scalar_t z_sq = z * z; + scalar_mat_t d(c_bpp_mn); + d(0, 0) = z_sq; + // first row + for (size_t i = 1; i < c_bpp_m; ++i) + d(i, 0) = d(i - 1, 0) * z_sq; + // all rows + for (size_t j = 1; j < CT::c_bpp_n; ++j) + for (size_t i = 0; i < c_bpp_m; ++i) + d(i, j) = d(i, j - 1) + d(i, j - 1); + + DBG_PRINT("Hs(d): " << d.calc_hs()); + + // calculate extended Vandermonde vector y = (1, y, y^2, ..., y^(mn+1)) (BP+ paper, page 18, Fig. 3) + // (calculate two more elements (1 and y^(mn+1)) for convenience) + scalar_vec_t y_powers(c_bpp_mn + 2); + y_powers[0] = 1; + for (size_t i = 1; i <= c_bpp_mn + 1; ++i) + y_powers[i] = y_powers[i - 1] * y; + + const scalar_t& y_mn_p1 = y_powers[c_bpp_mn + 1]; + + DBG_PRINT("Hs(y_powers): " << y_powers.calc_hs()); + + // aL_hat = aL - 1*z + scalar_vec_t aLs_hat = aLs - z; + // aL_hat = aR + d o y^leftarr + 1*z where y^leftarr = (y^n, y^(n-1), ..., y) (BP+ paper, page 18, Fig. 3) + scalar_vec_t aRs_hat = aRs + z; + for (size_t i = 0; i < c_bpp_mn; ++i) + aRs_hat[i] += d[i] * y_powers[c_bpp_mn - i]; + + DBG_PRINT("Hs(aLs_hat): " << aLs_hat.calc_hs()); + DBG_PRINT("Hs(aRs_hat): " << aRs_hat.calc_hs()); + + // calculate alpha_hat + // alpha_hat = alpha + SUM(z^(2j) * gamma_j * y^(mn+1)) for j = 1..m + // i.e. \hat{\alpha} = \alpha + y^{m n+1} \sum_{j = 1}^{m} z^{2j} \gamma_j + scalar_t alpha_hat = 0; + for (size_t i = 0; i < masks.size(); ++i) + alpha_hat += d(i, 0) * masks[i]; + alpha_hat = alpha + y_mn_p1 * alpha_hat; + + DBG_VAL_PRINT(alpha_hat); + + // calculate y^-1, y^-2, ... + const scalar_t y_inverse = y.reciprocal(); + scalar_vec_t y_inverse_powers(c_bpp_mn / 2 + 1); // the greatest power we need is c_bpp_mn/2 (at the first reduction round) + y_inverse_powers[0] = 1; + for (size_t i = 1, size = y_inverse_powers.size(); i < size; ++i) + y_inverse_powers[i] = y_inverse_powers[i - 1] * y_inverse; + + // prepare generator's vector + std::vector g(c_bpp_mn), h(c_bpp_mn); + for (size_t i = 0; i < c_bpp_mn; ++i) + { + g[i] = CT::get_generator(false, i); + h[i] = CT::get_generator(true, i); + } + + // WIP zk-argument called with zk-WIP(g, h, G, H, A_hat, aL_hat, aR_hat, alpha_hat) + + scalar_vec_t& a = aLs_hat; + scalar_vec_t& b = aRs_hat; + + sig.L.resize(c_bpp_log2_mn); + sig.R.resize(c_bpp_log2_mn); + + // zk-WIP reduction rounds (s.a. the preprint page 13 Fig. 1) + for (size_t n = c_bpp_mn / 2, ni = 0; n >= 1; n /= 2, ++ni) + { + DBG_PRINT(ENDL << "#" << ni); + + // zk-WIP(g, h, G, H, P, a, b, alpha) + + scalar_t dL = scalar_t::random(); + DBG_VAL_PRINT(dL); + scalar_t dR = scalar_t::random(); + DBG_VAL_PRINT(dR); + + // a = (a1, a2), b = (b1, b2) -- vectors of scalars + // cL = -- scalar + scalar_t cL = 0; + for (size_t i = 0; i < n; ++i) + cL += a[i] * y_powers[i + 1] * b[n + i]; + + DBG_VAL_PRINT(cL); + + // cR = * y^n -- scalar + scalar_t cR = 0; + for (size_t i = 0; i < n; ++i) + cR += a[n + i] * y_powers[i + 1] * b[i]; + cR *= y_powers[n]; + + DBG_VAL_PRINT(cR); + + // L = y^-n * a1 * g2 + b2 * h1 + cL * G + dL * H -- point + point_t sum = c_point_0; + for (size_t i = 0; i < n; ++i) + sum += a[i] * g[n + i]; + point_t L; + CT::calc_pedersen_commitment(cL, dL, L); + for (size_t i = 0; i < n; ++i) + L += b[n + i] * h[i]; + L += y_inverse_powers[n] * sum; + L *= c_scalar_1div8; + DBG_VAL_PRINT(L); + + // R = y^n * a2 * g1 + b1 * h2 + cR * G + dR * H -- point + sum.zero(); + for (size_t i = 0; i < n; ++i) + sum += a[n + i] * g[i]; + point_t R; + CT::calc_pedersen_commitment(cR, dR, R); + for (size_t i = 0; i < n; ++i) + R += b[i] * h[n + i]; + R += y_powers[n] * sum; + R *= c_scalar_1div8; + DBG_VAL_PRINT(R); + + // put L, R to the sig + L.to_public_key(sig.L[ni]); + R.to_public_key(sig.R[ni]); + + // update the transcript + hsc.add_scalar(e); + hsc.add_pub_key(sig.L[ni]); + hsc.add_pub_key(sig.R[ni]); + e = hsc.calc_hash(); + DBG_VAL_PRINT(e); + + // recalculate arguments for the next round + scalar_t e_squared = e * e; + scalar_t e_inverse = e.reciprocal(); + scalar_t e_inverse_squared = e_inverse * e_inverse; + scalar_t e_y_inv_n = e * y_inverse_powers[n]; + scalar_t e_inv_y_n = e_inverse * y_powers[n]; + + // g_hat = e^-1 * g1 + (e * y^-n) * g2 -- vector of points + for (size_t i = 0; i < n; ++i) + g[i] = e_inverse * g[i] + e_y_inv_n * g[n + i]; + + // h_hat = e * h1 + e^-1 * h2 -- vector of points + for (size_t i = 0; i < n; ++i) + h[i] = e * h[i] + e_inverse * h[n + i]; + + // P_hat = e^2 * L + P + e^-2 * R -- point + + // a_hat = e * a1 + e^-1 * y^n * a2 -- vector of scalars + for (size_t i = 0; i < n; ++i) + a[i] = e * a[i] + e_inv_y_n * a[n + i]; + + // b_hat = e^-1 * b1 + e * b2 -- vector of scalars + for (size_t i = 0; i < n; ++i) + b[i] = e_inverse * b[i] + e * b[n + i]; + + // alpha_hat = e^2 * dL + alpha + e^-2 * dR -- scalar + alpha_hat += e_squared * dL + e_inverse_squared * dR; + + // run next iteraton zk-WIP(g_hat, h_hat, G, H, P_hat, a_hat, b_hat, alpha_hat) + } + DBG_PRINT(""); + + // zk-WIP last round + scalar_t r = scalar_t::random(); + scalar_t s = scalar_t::random(); + scalar_t delta = scalar_t::random(); + scalar_t eta = scalar_t::random(); + DBG_VAL_PRINT(r); + DBG_VAL_PRINT(s); + DBG_VAL_PRINT(delta); + DBG_VAL_PRINT(eta); + + // A = r * g + s * h + (r y b + s y a) * G + delta * H -- point + point_t A = c_point_0; + CT::calc_pedersen_commitment(y * (r * b[0] + s * a[0]), delta, A); + A += r * g[0] + s * h[0]; + A *= c_scalar_1div8; + A.to_public_key(sig.A); + DBG_VAL_PRINT(A); + + // B = (r * y * s) * G + eta * H + point_t B = c_point_0; + CT::calc_pedersen_commitment(r * y * s, eta, B); + B *= c_scalar_1div8; + B.to_public_key(sig.B); + DBG_VAL_PRINT(B); + + // update the transcript + hsc.add_scalar(e); + hsc.add_pub_key(sig.A); + hsc.add_pub_key(sig.B); + e = hsc.calc_hash(); + DBG_VAL_PRINT(e); + + // finalize the signature + sig.r = r + e * a[0]; + sig.s = s + e * b[0]; + sig.delta = eta + e * delta + e * e * alpha_hat; + DBG_VAL_PRINT(sig.r); + DBG_VAL_PRINT(sig.s); + DBG_VAL_PRINT(sig.delta); + + return true; +#undef CHECK_AND_FAIL_WITH_ERROR_IF_FALSE + } // bpp_gen() + + + struct bpp_sig_commit_ref_t + { + bpp_sig_commit_ref_t(const bpp_signature& sig, const std::vector& commitments) + : sig(sig) + , commitments(commitments) + {} + const bpp_signature& sig; + const std::vector& commitments; + }; + + + template + bool bpp_verify(const std::vector& sigs, uint8_t* p_err = nullptr) + { +#define CHECK_AND_FAIL_WITH_ERROR_IF_FALSE(cond, err_code) \ + if (!(cond)) { LOG_PRINT_RED("bpp_verify: \"" << #cond << "\" is false at " << LOCATION_SS << ENDL << "error code = " << err_code, LOG_LEVEL_3); \ + if (p_err) { *p_err = err_code; } return false; } + + DBG_PRINT(ENDL << " . . . . bpp_verify() . . . . "); + + const size_t kn = sigs.size(); + CHECK_AND_FAIL_WITH_ERROR_IF_FALSE(kn > 0, 1); + + struct intermediate_element_t + { + scalar_t y; + scalar_t z; + scalar_t z_sq; + scalar_vec_t e; + scalar_vec_t e_sq; + scalar_t e_final; + scalar_t e_final_sq; + size_t inv_e_offset; // offset in batch_for_inverse + size_t inv_y_offset; // offset in batch_for_inverse + size_t c_bpp_log2_m; + size_t c_bpp_m; + size_t c_bpp_mn; + point_t A; + point_t A0; + point_t B; + std::vector L; + std::vector R; + }; + std::vector interms(kn); + + size_t c_bpp_log2_m_max = 0; + for (size_t k = 0; k < kn; ++k) + { + const bpp_sig_commit_ref_t& bsc = sigs[k]; + const bpp_signature& sig = bsc.sig; + CHECK_AND_FAIL_WITH_ERROR_IF_FALSE(bsc.commitments.size() > 0, 2); + CHECK_AND_FAIL_WITH_ERROR_IF_FALSE(sig.L.size() > 0 && sig.L.size() == sig.R.size(), 3); + CHECK_AND_FAIL_WITH_ERROR_IF_FALSE(sig.r.is_reduced() && sig.s.is_reduced() && sig.delta.is_reduced(), 4); + + intermediate_element_t& interm = interms[k]; + interm.c_bpp_log2_m = constexpr_ceil_log2(bsc.commitments.size()); + if (c_bpp_log2_m_max < interm.c_bpp_log2_m) + c_bpp_log2_m_max = interm.c_bpp_log2_m; + + CHECK_AND_FAIL_WITH_ERROR_IF_FALSE(sig.L.size() == interm.c_bpp_log2_m + CT::c_bpp_log2_n, 5); + + interm.c_bpp_m = 1ull << interm.c_bpp_log2_m; + interm.c_bpp_mn = interm.c_bpp_m * CT::c_bpp_n; + + CHECK_AND_FAIL_WITH_ERROR_IF_FALSE(interm.A0.from_public_key(sig.A0), 6); + CHECK_AND_FAIL_WITH_ERROR_IF_FALSE(interm.A.from_public_key(sig.A), 7); + CHECK_AND_FAIL_WITH_ERROR_IF_FALSE(interm.B.from_public_key(sig.B), 8); + interm.L.resize(sig.L.size()); + interm.R.resize(sig.R.size()); + for (size_t i = 0; i < interm.L.size(); ++i) + { + CHECK_AND_FAIL_WITH_ERROR_IF_FALSE(interm.L[i].from_public_key(sig.L[i]), 9); + CHECK_AND_FAIL_WITH_ERROR_IF_FALSE(interm.R[i].from_public_key(sig.R[i]), 10); + } + } + const size_t c_bpp_m_max = 1ull << c_bpp_log2_m_max; + const size_t c_bpp_mn_max = c_bpp_m_max * CT::c_bpp_n; + const size_t c_bpp_LR_size_max = c_bpp_log2_m_max + CT::c_bpp_log2_n; + + + // + // prepare stuff + // + /* + std::vector g(c_bpp_mn_max), h(c_bpp_mn_max); + for (size_t i = 0; i < c_bpp_mn_max; ++i) + { + g[i] = CT::get_generator(false, i); + h[i] = CT::get_generator(true, i); + } + */ + + scalar_vec_t batch_for_inverse; + batch_for_inverse.reserve(kn + kn * c_bpp_LR_size_max); + + + for (size_t k = 0; k < kn; ++k) + { + DBG_PRINT(ENDL << "SIG #" << k); + const bpp_sig_commit_ref_t& bsc = sigs[k]; + const bpp_signature& sig = bsc.sig; + intermediate_element_t& interm = interms[k]; + + // restore y and z + // using e as Fiat-Shamir transcript + scalar_t e = CT::get_initial_transcript(); + DBG_PRINT("initial transcript: " << e); + hash_helper_t::hs_t hsc; + CT::update_transcript(hsc, e, bsc.commitments); + // calculate scalar challenges y and z + hsc.add_scalar(e); + hsc.add_pub_key(sig.A0); + hsc.assign_calc_hash(interm.y); + interm.z = hash_helper_t::hs(interm.y); + interm.z_sq = interm.z * interm.z; + DBG_VAL_PRINT(interm.y); + DBG_VAL_PRINT(interm.z); + e = interm.z; // transcript for further steps + + interm.inv_y_offset = batch_for_inverse.size(); + batch_for_inverse.push_back(interm.y); + interm.inv_e_offset = batch_for_inverse.size(); + + interm.e.resize(sig.L.size()); + interm.e_sq.resize(sig.L.size()); + + for (size_t i = 0; i < sig.L.size(); ++i) + { + hsc.add_scalar(e); + hsc.add_pub_key(sig.L[i]); + hsc.add_pub_key(sig.R[i]); + hsc.assign_calc_hash(e); + interm.e[i] = e; + interm.e_sq[i] = e * e; + DBG_PRINT("e[" << i << "]: " << e); + batch_for_inverse.push_back(e); + } + + hsc.add_scalar(e); + hsc.add_pub_key(sig.A); + hsc.add_pub_key(sig.B); + hsc.assign_calc_hash(interm.e_final); + interm.e_final_sq = interm.e_final * interm.e_final; + DBG_VAL_PRINT(interm.e_final); + } + + batch_for_inverse.invert(); + + // Notation: + // 1_vec ^ n = (1, 1, 1, ..., 1) + // 2_vec ^ n = (2^0, 2^1, 2^2, ..., 2^(n-1)) + // -1_vec ^ n = ((-1)^0, (-1)^1, (-1)^2, ... (-1)^(n-1)) = (1, -1, 1, -1, ...) + // y<^n = (y^n, y^(n-1), ..., y^1) + // y>^n = (y^1, y^2, ..., y^n) + + // from page 13, Fig 1: + // Verifier outputs Accept IFF the following equality holds (single proof): + // P^e^2 * A^e * B == g ^ (r' e) * h ^ (s' e) * G ^ (r' y s') * H ^ delta' + // (where g and h are calculated in each round) + // The same equation in additive notation: + // e^2 * P + e * A + B == (r' * e) * g + (s' * e) * h + (r' y s') * G + delta' * H + // <=> + // (r' * e) * g + (s' * e) * h + (r' y s') * G + delta' * H - e^2 * P - e * A - B == 0 (*) + // where A, B, r', s', delta' is taken from the signature + // and P_{k+1} = e^2 * L_k + P_k + e^-2 * R_k for all rounds + // + // from page 18, Fig 3: + // P and V computes: + // A_hat = A0 + (- 1^(mn) * z) * g + (d o y<^(mn) + 1^(mn) * z) * h + + // + y^(mn+1) * (SUM{j=1..m} z^(2j) * V_j) + + // + (z*SUM(y^>mn) - z*y^(mn+1)*SUM(d) - z^2 * SUM(y^>mn)) * G + // (calculated once) + // + // As suggested in Section 6.1 "Practical Optimizations": + // 1) g and h exponentianions can be optimized in order not to be calculated at each round as the following (page 20): + // + // (r' * e * s_vec) * g + (s' * e * s'_vec) * h + (r' y s') * G + delta' * H - + // - e^2 * A_hat + // - SUM{j=1..log(n)}(e_final^2 * e_j^2 * L_j + e_final^2 * e_j^-2 * R_j) + // - e * A - B = 0 (**) + // + // where: + // g, h - vector of fixed generators + // s_vec_i = y^(1-i) * PROD{j=1..log(n)}(e_j ^ b(i,j)) + // s'_vec_i = PROD{j=1..log(n)}(e_j ^ -b(i,j)) + // b(i, j) = { 2 * ((1<<(j-1)) & (i-1)) - 1) (counting both from 1) (page 20) + // b(i, j) = { 2 * ((1< + + // (r' * e * s_vec) * g + (s' * e * s'_vec) * h + (r' y s') * G + delta' * H - + // - e^2 * (A0 + (- 1^(mn) * z) * g + (d o y<^(mn) + 1^(mn) * z) * h + + // + y^(mn+1) * (SUM{j=1..m} z^(2j) * V_j) + + // + (z*SUM(y^>mn) - z*y^(mn+1)*SUM(d) - z^2 * SUM(y^>mn)) * G + // ) + // - SUM{j=1..log(n)}(e_final^2 * e_j^2 * L_j + e_final^2 * e_j^-2 * R_j) + // - e * A - B = 0 + + // => + + // (for single signature) + // + // (r' * e * s_vec - e^2 * (- 1_vec^(mn) * z)) * g | these are + // + (s' * e * s'_vec - e^2 * (d o y<^(mn) + 1_vec^(mn) * z)) * h | fixed generators + // + (r' y s' - e^2 * ((z - z^2)*SUM(y^>mn) - z*y^(mn+1)*SUM(d)) * G | across all + // + delta' * H | the signatures + // + // - e^2 * A0 + // - e^2 * y^(mn+1) * (SUM{j=1..m} z^(2j) * V_j)) + // - e^2 * SUM{j=1..log(n)}(e_j^2 * L_j + e_j^-2 * R_j) + // - e * A - B = 0 (***) + // + // All (***) will be muptiplied by random weightning factor and then summed up. + + // Calculate cummulative sclalar multiplicand for fixed generators across all the sigs. + scalar_vec_t g_scalars; + g_scalars.resize(c_bpp_mn_max, 0); + scalar_vec_t h_scalars; + h_scalars.resize(c_bpp_mn_max, 0); + scalar_t G_scalar = 0; + scalar_t H_scalar = 0; + point_t summand = c_point_0; + + for (size_t k = 0; k < kn; ++k) + { + DBG_PRINT(ENDL << "SIG #" << k); + const bpp_sig_commit_ref_t& bsc = sigs[k]; + const bpp_signature& sig = bsc.sig; + intermediate_element_t& interm = interms[k]; + + // random weightning factor for speed-optimized batch verification (preprint page 20) + const scalar_t rwf = scalar_t::random(); + DBG_PRINT("rwf: " << rwf); + + // prepare d vector (see also d structure description in proof function) + scalar_mat_t d(interm.c_bpp_mn); + d(0, 0) = interm.z_sq; + // first row + for (size_t i = 1; i < interm.c_bpp_m; ++i) + d(i, 0) = d(i - 1, 0) * interm.z_sq; + // all rows + for (size_t j = 1; j < CT::c_bpp_n; ++j) + for (size_t i = 0; i < interm.c_bpp_m; ++i) + d(i, j) = d(i, j - 1) + d(i, j - 1); + // sum(d) (see also note in proof function for this) + static const scalar_t c_scalar_2_power_n_minus_1 = { 0xffffffffffffffff, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000 }; + const scalar_t sum_d = c_scalar_2_power_n_minus_1 * sum_of_powers(interm.z_sq, interm.c_bpp_log2_m); + + DBG_PRINT("Hs(d): " << d.calc_hs()); + DBG_PRINT("sum(d): " << sum_d); + + const scalar_t& y_inv = batch_for_inverse[interm.inv_y_offset]; + auto get_e_inv = [&](size_t i) { return batch_for_inverse[interm.inv_e_offset + i]; }; // i belongs to [0; L.size()-1] + + // prepare s_vec (unlike the paper here we moved y-component out of s_vec for convenience, so s_vec'[x] = s_vec[~x & (MN-1)]) + // complexity (sc_mul's): MN+2*log2(MN)-2 + // the idea is the following: + // s_vec[00000b] = ... * (e_4)^-1 * (e_3)^-1 * (e_2)^-1 * (e_1)^-1 * (e_0)^-1 + // s_vec[00101b] = ... * (e_4)^-1 * (e_3)^-1 * (e_2)^+1 * (e_1)^-1 * (e_0)^+1 + const size_t log2_mn = sig.L.size(); // at the beginning we made sure that sig.L.size() == c_bpp_log2_m + c_bpp_log2_n + scalar_vec_t s_vec(interm.c_bpp_mn); + s_vec[0] = get_e_inv(0); + for (size_t i = 1; i < log2_mn; ++i) + s_vec[0] *= get_e_inv(i); // s_vec[0] = (e_0)^-1 * (e_1)^-1 * .. (e_{log2_mn-1})^-1 + DBG_PRINT("[0] " << s_vec[0]); + for (size_t i = 1; i < interm.c_bpp_mn; ++i) + { + size_t base_el_index = i & (i - 1); // base element index: 0, 0, 2, 0, 4, 4, 6, 0, 8, 8, 10... base element differs in one bit (0) from the current one (1) + size_t bit_index = log2_mn - calc_lsb_32((uint32_t)i) - 1; // the bit index where current element has the difference with the base + s_vec[i] = s_vec[base_el_index] * interm.e_sq[bit_index]; // (e_j)^-1 * (e_j)^2 = (e_j)^+1 + DBG_PRINT("[" << i << "] " << " " << base_el_index << ", " << bit_index << " : " << s_vec[i]); + } + + // prepare y_inv vector + scalar_vec_t y_inverse_powers(interm.c_bpp_mn); + y_inverse_powers[0] = 1; + for (size_t i = 1; i < interm.c_bpp_mn; ++i) + y_inverse_powers[i] = y_inverse_powers[i - 1] * y_inv; + + // y^(mn+1) + scalar_t y_power_mnp1 = interm.y; + for (size_t i = 0; i < log2_mn; ++i) + y_power_mnp1 *= y_power_mnp1; + y_power_mnp1 *= interm.y; + DBG_VAL_PRINT(y_power_mnp1); + + // now calculate all multiplicands for common generators + + // g vector multiplicands: + // rwf * (r' * e * (1, y^-1, y^-2, ...) o s_vec + e^2 * z) = + // rwf * r' * e * ((1, y^-1, ...) o s_vec) + rwf * e^2 * z * (1, 1, ...) + scalar_t rwf_e_sq_z = rwf * interm.e_final_sq * interm.z; + scalar_t rwf_r_e = rwf * interm.e_final * sig.r; + for (size_t i = 0; i < interm.c_bpp_mn; ++i) + g_scalars[i] += rwf_r_e * y_inverse_powers[i] * s_vec[i] + rwf_e_sq_z; + + DBG_PRINT("Hs(g_scalars): " << g_scalars.calc_hs()); + + // h vector multiplicands: + // rwf * (s' * e * s'_vec - e^2 * (d o y<^(mn) + 1_vec^(mn) * z)) + // rwf * s' * e * s'_vec - rwf * e^2 * z * (1, 1...) - rwf * e^2 * (d o y<^(mn)) + //scalar_t rwf_e_sq_z = rwf * interm.e_final_sq * interm.z; + scalar_t rwf_s_e = rwf * sig.s * interm.e_final; + scalar_t rwf_e_sq_y = rwf * interm.e_final_sq * interm.y; + for (size_t i = interm.c_bpp_mn - 1; i != SIZE_MAX; --i) + { + h_scalars[i] += rwf_s_e * s_vec[interm.c_bpp_mn - 1 - i] - rwf_e_sq_z - rwf_e_sq_y * d[i]; + rwf_e_sq_y *= interm.y; + } + + DBG_PRINT("Hs(h_scalars): " << h_scalars.calc_hs()); + + // G point multiplicands: + // rwf * (r' y s' - e ^ 2 * ((z - z ^ 2)*SUM(y^>mn) - z * y^(mn+1) * SUM(d)) = + // = rwf * r' y s' - rwf * e^2 * (z - z ^ 2)*SUM(y^>mn) + rwf * e^2 * z * y^(mn+1) * SUM(d) + G_scalar += rwf * sig.r * interm.y * sig.s + rwf_e_sq_y * sum_d * interm.z; + G_scalar -= rwf * interm.e_final_sq * (interm.z - interm.z_sq) * sum_of_powers(interm.y, log2_mn); + DBG_PRINT("sum_y: " << sum_of_powers(interm.y, log2_mn)); + DBG_PRINT("G_scalar: " << G_scalar); + + // H point multiplicands: + // rwf * delta + H_scalar += rwf * sig.delta; + DBG_PRINT("H_scalar: " << H_scalar); + + // uncommon generators' multiplicands + point_t summand_8 = c_point_0; // this summand to be multiplied by 8 before adding to the main summand + // - rwf * e^2 * A0 + summand_8 -= rwf * interm.e_final_sq * interm.A0; + DBG_PRINT("A0_scalar: " << c_scalar_Lm1 * interm.e_final_sq * rwf); + + // - rwf * e^2 * y^(mn+1) * (SUM{j=1..m} (z^2)^j * V_j)) + scalar_t e_sq_y_mn1_z_sq_power = rwf * interm.e_final_sq * y_power_mnp1; + for (size_t j = 0; j < bsc.commitments.size(); ++j) + { + e_sq_y_mn1_z_sq_power *= interm.z_sq; + summand_8 -= e_sq_y_mn1_z_sq_power * bsc.commitments[j]; + DBG_PRINT("V_scalar[" << j << "]: " << c_scalar_Lm1 * e_sq_y_mn1_z_sq_power); + } + + // - rwf * e^2 * SUM{j=1..log(n)}(e_j^2 * L_j + e_j^-2 * R_j) + scalar_t rwf_e_sq = rwf * interm.e_final_sq; + for (size_t j = 0; j < log2_mn; ++j) + { + summand_8 -= rwf_e_sq * (interm.e_sq[j] * interm.L[j] + get_e_inv(j) * get_e_inv(j) * interm.R[j]); + DBG_PRINT("L_scalar[" << j << "]: " << c_scalar_Lm1 * rwf_e_sq * interm.e_sq[j]); + DBG_PRINT("R_scalar[" << j << "]: " << c_scalar_Lm1 * rwf_e_sq * get_e_inv(j) * get_e_inv(j)); + } + + // - rwf * e * A - rwf * B = 0 + summand_8 -= rwf * interm.e_final * interm.A + rwf * interm.B; + DBG_PRINT("A_scalar: " << c_scalar_Lm1 * rwf * interm.e_final); + DBG_PRINT("B_scalar: " << c_scalar_Lm1 * rwf); + + summand_8.modify_mul8(); + summand += summand_8; + } + + point_t GH_exponents = c_point_0; + CT::calc_pedersen_commitment(G_scalar, H_scalar, GH_exponents); + bool result = multiexp_and_check_being_zero(g_scalars, h_scalars, summand + GH_exponents); + if (result) + DBG_PRINT(ENDL << " . . . . bpp_verify() -- SUCCEEDED!!!" << ENDL); + return result; +#undef CHECK_AND_FAIL_WITH_ERROR_IF_FALSE + } + +} // namespace crypto diff --git a/src/crypto/range_proofs.cpp b/src/crypto/range_proofs.cpp index b6750a09..783a0c2b 100644 --- a/src/crypto/range_proofs.cpp +++ b/src/crypto/range_proofs.cpp @@ -6,7 +6,4 @@ namespace crypto { - const point_t& bpp_crypto_trait_zano::bpp_H = c_point_H; - - } diff --git a/src/crypto/range_proofs.h b/src/crypto/range_proofs.h index b3d04d68..623c5af0 100644 --- a/src/crypto/range_proofs.h +++ b/src/crypto/range_proofs.h @@ -1,14 +1,9 @@ -// Copyright (c) 2021 Zano Project (https://zano.org/) -// Copyright (c) 2021 sowle (val@zano.org, crypto.sowle@gmail.com) +// Copyright (c) 2021-2022 Zano Project (https://zano.org/) +// Copyright (c) 2021-2022 sowle (val@zano.org, crypto.sowle@gmail.com) // Distributed under the MIT/X11 software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. #pragma once -// -// This file contains the implementation of range proof protocol. -// Namely, Bulletproofs+ https://eprint.iacr.org/2020/735.pdf -// - #include "epee/include/misc_log_ex.h" #include "crypto-sugar.h" @@ -28,27 +23,23 @@ namespace crypto return result; } - constexpr size_t c_bpp_log2_n = 6; - constexpr size_t c_bpp_n = 64; // 2^64 is the upper bound for the witness's range - constexpr size_t c_bpp_values_max = 16; // maximum number of elements in BP+ proof, i.e. max allowed BP+ outputs - constexpr size_t c_bpp_mn_max = c_bpp_n * c_bpp_values_max; + + // returns greatest k, s.t. 2**k <= v + // tests in crypto_tests_range_proofs.h + constexpr size_t constexpr_floor_log2(size_t v) + { + return v <= 1 ? 0 : constexpr_floor_log2(v >> 1) + 1; + } // returns smallest k, s.t. v <= 2**k - inline size_t calc_exp_power_of_2_upper_bound(size_t v) + // tests in crypto_tests_range_proofs.h + constexpr size_t constexpr_ceil_log2(size_t v) { - constexpr size_t max_v = (SIZE_MAX >> 1) + 1; - //if (v > max_v) - // return 0; - - size_t pow = 1, result = 0; - while (v > pow) - { - pow <<= 1; - ++result; - } - return result; + return v <= 1 ? 0 : constexpr_floor_log2(v - 1) + 1; } + + // returns least significant bit uing de Bruijn sequence // http://graphics.stanford.edu/~seander/bithacks.html inline uint8_t calc_lsb_32(uint32_t v) @@ -61,17 +52,28 @@ namespace crypto return multiply_de_bruijn_bit_position[((uint32_t)((v & -(int32_t)v) * 0x077CB531U)) >> 27]; } - + //////////////////////////////////////// // crypto trait for Zano //////////////////////////////////////// + template struct bpp_crypto_trait_zano { + static constexpr size_t c_bpp_n = N; // the upper bound for the witness's range + static constexpr size_t c_bpp_values_max = values_max; // maximum number of elements in BP+ proof, i.e. max allowed BP+ outputs + static constexpr size_t c_bpp_log2_n = constexpr_ceil_log2(c_bpp_n); + static constexpr size_t c_bpp_mn_max = c_bpp_n * c_bpp_values_max; + static void calc_pedersen_commitment(const scalar_t& value, const scalar_t& mask, point_t& commitment) { commitment = value * c_point_G + mask * c_point_H; } + static void calc_pedersen_commitment_2(const scalar_t& value, const scalar_t& mask1, const scalar_t& mask2, point_t& commitment) + { + commitment = value * c_point_G + mask1 * c_point_H + mask2 * c_point_H2; + } + static const scalar_t& get_initial_transcript() { static scalar_t value = hash_helper_t::hs("Zano BP+ initial transcript"); @@ -86,6 +88,7 @@ namespace crypto e = hsc.calc_hash(); } + // TODO: refactor with proper OOB handling static const point_t& get_generator(bool select_H, size_t index) { if (index >= c_bpp_mn_max) @@ -108,332 +111,22 @@ namespace crypto } static const point_t& bpp_H; - }; + static const point_t& bpp_H2; + }; // struct bpp_crypto_trait_zano + + template + const point_t& bpp_crypto_trait_zano::bpp_H = c_point_H; + + template + const point_t& bpp_crypto_trait_zano::bpp_H2 = c_point_H2; - struct bpp_signature - { - std::vector L; // size = log_2(m * n) - std::vector R; - public_key A0; - public_key A; - public_key B; - scalar_t r; - scalar_t s; - scalar_t delta; - }; - -#define DBG_VAL_PRINT(x) std::cout << #x ": " << x << ENDL -#define DBG_PRINT(x) std::cout << x << ENDL - - template - bool bpp_gen(const std::vector& values, const scalar_vec_t& masks, bpp_signature& sig, std::vector& commitments, uint8_t* p_err = nullptr) - { -#define CHECK_AND_FAIL_WITH_ERROR_IF_FALSE(cond, err_code) \ - if (!(cond)) { LOG_PRINT_RED("bpp_gen: \"" << #cond << "\" is false at " << LOCATION_SS << ENDL << "error code = " << err_code, LOG_LEVEL_3); \ - if (p_err) { *p_err = err_code; } return false; } - - CHECK_AND_FAIL_WITH_ERROR_IF_FALSE(values.size() > 0 && values.size() <= c_bpp_values_max && values.size() == masks.size(), 1); - CHECK_AND_FAIL_WITH_ERROR_IF_FALSE(masks.is_reduced(), 3); - - const size_t c_bpp_log2_m = calc_exp_power_of_2_upper_bound(values.size()); - const size_t c_bpp_m = 1ull << c_bpp_log2_m; - const size_t c_bpp_mn = c_bpp_m * c_bpp_n; - const size_t c_bpp_log2_mn = c_bpp_log2_m + c_bpp_log2_n; - - // pre-multiply all output points by c_scalar_1div8 - // in order to enforce these points to be in the prime-order subgroup (after mul by 8 in bpp_verify()) - - // calc commitments vector as commitments[i] = 1/8 * values[i] * G + 1/8 * masks[i] * H - commitments.resize(values.size()); - for (size_t i = 0; i < values.size(); ++i) - CT::calc_pedersen_commitment(scalar_t(values[i]) * c_scalar_1div8, masks[i] * c_scalar_1div8, commitments[i]); - - - // s.a. BP+ paper, page 15, eq. 11 - // decompose v into aL and aR: - // v = aL o (1, 2, 2^2, ..., 2^n-1), o - component-wise product aka Hadamard product - // aR = aL - (1, 1, ... 1) - // aR o aL = 0 - - // aLs = (aL_0, aL_1, ..., aL_m-1) -- `bit` matrix of c_bpp_m x c_bpp_n, each element is a scalar - - scalar_mat_t aLs(c_bpp_mn), aRs(c_bpp_mn); - aLs.zero(); - aRs.zero(); - // m >= values.size, first set up [0..values.size-1], then -- [values.size..m-1] (padding area) - for (size_t i = 0; i < values.size(); ++i) - { - uint64_t v = values[i]; - for (size_t j = 0; j < c_bpp_n; ++j) - { - if (v & 1) - aLs(i, j) = c_scalar_1; // aL = 1, aR = 0 - else - aRs(i, j) = c_scalar_Lm1; // aL = 0, aR = -1 - v >>= 1; - } - } - - for (size_t i = values.size(); i < c_bpp_m; ++i) - for (size_t j = 0; j < c_bpp_n; ++j) - aRs(i, j) = c_scalar_Lm1; // aL = 0, aR = -1 - - - // using e as Fiat-Shamir transcript - scalar_t e = CT::get_initial_transcript(); - DBG_PRINT("initial transcript: " << e); - - hash_helper_t::hs_t hsc; - CT::update_transcript(hsc, e, commitments); - - // BP+ paper, page 15: The prover begins with sending A = g^aL h^aR h^alpha (group element) - // so we calculate A0 = alpha * H + SUM(aL_i * G_i) + SUM(aR_i * H_i) - - scalar_t alpha = scalar_t::random(); - point_t A0 = alpha * CT::bpp_H; - - for (size_t i = 0; i < c_bpp_mn; ++i) - A0 += aLs[i] * CT::get_generator(false, i) + aRs[i] * CT::get_generator(true, i); - - // part of 1/8 defense scheme - A0 *= c_scalar_1div8; - A0.to_public_key(sig.A0); - - DBG_VAL_PRINT(alpha); - DBG_VAL_PRINT(A0); - - // calculate scalar challenges y and z - hsc.add_scalar(e); - hsc.add_pub_key(sig.A0); - scalar_t y = hsc.calc_hash(); - scalar_t z = hash_helper_t::hs(y); - e = z; // transcript for further steps - DBG_VAL_PRINT(y); - DBG_VAL_PRINT(z); - - // Computing vector d for aggregated version of the protocol (BP+ paper, page 17) - // (note: elements is stored column-by-column in memory) - // d = | 1 * z^(2*1), 1 * z^(2*2), 1 * z^(2*3), ..., 1 * z^(2*m) | - // | 2 * z^(2*1), 2 * z^(2*2), 2 * z^(2*3), ..., 2 * z^(2*m) | - // | 4 * z^(2*1), 4 * z^(2*2), 4 * z^(2*3), ..., 4 * z^(2*m) | - // | ....................................................................................... | - // | 2^(n-1) * z^(2*1), 2^(n-1) * z^(2*2), 2^(n-1) * z^(2*3), ..., 2^(n-1) * z^(2*m)) | - // Note: sum(d_i) = (2^n - 1) * ((z^2)^1 + (z^2)^2 + ... (z^2)^m)) = (2^n-1) * sum_of_powers(x^2, log(m)) - - scalar_t z_sq = z * z; - scalar_mat_t d(c_bpp_mn); - d(0, 0) = z_sq; - // first row - for (size_t i = 1; i < c_bpp_m; ++i) - d(i, 0) = d(i - 1, 0) * z_sq; - // all rows - for (size_t j = 1; j < c_bpp_n; ++j) - for (size_t i = 0; i < c_bpp_m; ++i) - d(i, j) = d(i, j - 1) + d(i, j - 1); - - DBG_PRINT("Hs(d): " << d.calc_hs()); - - // calculate extended Vandermonde vector y = (1, y, y^2, ..., y^(mn+1)) (BP+ paper, page 18, Fig. 3) - // (calculate two more elements (1 and y^(mn+1)) for convenience) - scalar_vec_t y_powers(c_bpp_mn + 2); - y_powers[0] = 1; - for (size_t i = 1; i <= c_bpp_mn + 1; ++i) - y_powers[i] = y_powers[i - 1] * y; - - const scalar_t& y_mn_p1 = y_powers[c_bpp_mn + 1]; - - DBG_PRINT("Hs(y_powers): " << y_powers.calc_hs()); - - // aL_hat = aL - 1*z - scalar_vec_t aLs_hat = aLs - z; - // aL_hat = aR + d o y^leftarr + 1*z where y^leftarr = (y^n, y^(n-1), ..., y) (BP+ paper, page 18, Fig. 3) - scalar_vec_t aRs_hat = aRs + z; - for (size_t i = 0; i < c_bpp_mn; ++i) - aRs_hat[i] += d[i] * y_powers[c_bpp_mn - i]; - - DBG_PRINT("Hs(aLs_hat): " << aLs_hat.calc_hs()); - DBG_PRINT("Hs(aRs_hat): " << aRs_hat.calc_hs()); - - // calculate alpha_hat - // alpha_hat = alpha + SUM(z^(2j) * gamma_j * y^(mn+1)) for j = 1..m - // i.e. \hat{\alpha} = \alpha + y^{m n+1} \sum_{j = 1}^{m} z^{2j} \gamma_j - scalar_t alpha_hat = 0; - for (size_t i = 0; i < masks.size(); ++i) - alpha_hat += d(i, 0) * masks[i]; - alpha_hat = alpha + y_mn_p1 * alpha_hat; - - DBG_VAL_PRINT(alpha_hat); - - // calculate y^-1, y^-2, ... - const scalar_t y_inverse = y.reciprocal(); - scalar_vec_t y_inverse_powers(c_bpp_mn / 2 + 1); // the greatest power we need is c_bpp_mn/2 (at the first reduction round) - y_inverse_powers[0] = 1; - for (size_t i = 1, size = y_inverse_powers.size(); i < size; ++i) - y_inverse_powers[i] = y_inverse_powers[i - 1] * y_inverse; - - // prepare generator's vector - std::vector g(c_bpp_mn), h(c_bpp_mn); - for (size_t i = 0; i < c_bpp_mn; ++i) - { - g[i] = CT::get_generator(false, i); - h[i] = CT::get_generator(true, i); - } - - // WIP zk-argument called with zk-WIP(g, h, G, H, A_hat, aL_hat, aR_hat, alpha_hat) - - scalar_vec_t& a = aLs_hat; - scalar_vec_t& b = aRs_hat; - - sig.L.resize(c_bpp_log2_mn); - sig.R.resize(c_bpp_log2_mn); - - // zk-WIP reduction rounds (s.a. the preprint page 13 Fig. 1) - for (size_t n = c_bpp_mn / 2, ni = 0; n >= 1; n /= 2, ++ni) - { - DBG_PRINT(ENDL << "#" << ni); - - // zk-WIP(g, h, G, H, P, a, b, alpha) - - scalar_t dL = scalar_t::random(); - DBG_VAL_PRINT(dL); - scalar_t dR = scalar_t::random(); - DBG_VAL_PRINT(dR); - - // a = (a1, a2), b = (b1, b2) -- vectors of scalars - // cL = -- scalar - scalar_t cL = 0; - for (size_t i = 0; i < n; ++i) - cL += a[i] * y_powers[i + 1] * b[n + i]; - - DBG_VAL_PRINT(cL); - - // cR = * y^n -- scalar - scalar_t cR = 0; - for (size_t i = 0; i < n; ++i) - cR += a[n + i] * y_powers[i + 1] * b[i]; - cR *= y_powers[n]; - - DBG_VAL_PRINT(cR); - - // L = y^-n * a1 * g2 + b2 * h1 + cL * G + dL * H -- point - point_t sum = c_point_0; - for (size_t i = 0; i < n; ++i) - sum += a[i] * g[n + i]; - point_t L; - CT::calc_pedersen_commitment(cL, dL, L); - for (size_t i = 0; i < n; ++i) - L += b[n + i] * h[i]; - L += y_inverse_powers[n] * sum; - L *= c_scalar_1div8; - DBG_VAL_PRINT(L); - - // R = y^n * a2 * g1 + b1 * h2 + cR * G + dR * H -- point - sum.zero(); - for (size_t i = 0; i < n; ++i) - sum += a[n + i] * g[i]; - point_t R; - CT::calc_pedersen_commitment(cR, dR, R); - for (size_t i = 0; i < n; ++i) - R += b[i] * h[n + i]; - R += y_powers[n] * sum; - R *= c_scalar_1div8; - DBG_VAL_PRINT(R); - - // put L, R to the sig - L.to_public_key(sig.L[ni]); - R.to_public_key(sig.R[ni]); - - // update the transcript - hsc.add_scalar(e); - hsc.add_pub_key(sig.L[ni]); - hsc.add_pub_key(sig.R[ni]); - e = hsc.calc_hash(); - DBG_VAL_PRINT(e); - - // recalculate arguments for the next round - scalar_t e_squared = e * e; - scalar_t e_inverse = e.reciprocal(); - scalar_t e_inverse_squared = e_inverse * e_inverse; - scalar_t e_y_inv_n = e * y_inverse_powers[n]; - scalar_t e_inv_y_n = e_inverse * y_powers[n]; - - // g_hat = e^-1 * g1 + (e * y^-n) * g2 -- vector of points - for (size_t i = 0; i < n; ++i) - g[i] = e_inverse * g[i] + e_y_inv_n * g[n + i]; - - // h_hat = e * h1 + e^-1 * h2 -- vector of points - for (size_t i = 0; i < n; ++i) - h[i] = e * h[i] + e_inverse * h[n + i]; - - // P_hat = e^2 * L + P + e^-2 * R -- point - - // a_hat = e * a1 + e^-1 * y^n * a2 -- vector of scalars - for (size_t i = 0; i < n; ++i) - a[i] = e * a[i] + e_inv_y_n * a[n + i]; - - // b_hat = e^-1 * b1 + e * b2 -- vector of scalars - for (size_t i = 0; i < n; ++i) - b[i] = e_inverse * b[i] + e * b[n + i]; - - // alpha_hat = e^2 * dL + alpha + e^-2 * dR -- scalar - alpha_hat += e_squared * dL + e_inverse_squared * dR; - - // run next iteraton zk-WIP(g_hat, h_hat, G, H, P_hat, a_hat, b_hat, alpha_hat) - } - DBG_PRINT(""); - - // zk-WIP last round - scalar_t r = scalar_t::random(); - scalar_t s = scalar_t::random(); - scalar_t delta = scalar_t::random(); - scalar_t eta = scalar_t::random(); - DBG_VAL_PRINT(r); - DBG_VAL_PRINT(s); - DBG_VAL_PRINT(delta); - DBG_VAL_PRINT(eta); - - // A = r * g + s * h + (r y b + s y a) * G + delta * H -- point - point_t A = c_point_0; - CT::calc_pedersen_commitment(y * (r * b[0] + s * a[0]), delta, A); - A += r * g[0] + s * h[0]; - A *= c_scalar_1div8; - A.to_public_key(sig.A); - DBG_VAL_PRINT(A); - - // B = (r * y * s) * G + eta * H - point_t B = c_point_0; - CT::calc_pedersen_commitment(r * y * s, eta, B); - B *= c_scalar_1div8; - B.to_public_key(sig.B); - DBG_VAL_PRINT(B); - - // update the transcript - hsc.add_scalar(e); - hsc.add_pub_key(sig.A); - hsc.add_pub_key(sig.B); - e = hsc.calc_hash(); - DBG_VAL_PRINT(e); - - // finalize the signature - sig.r = r + e * a[0]; - sig.s = s + e * b[0]; - sig.delta = eta + e * delta + e * e * alpha_hat; - DBG_VAL_PRINT(sig.r); - DBG_VAL_PRINT(sig.s); - DBG_VAL_PRINT(sig.delta); - - return true; -#undef CHECK_AND_FAIL_WITH_ERROR_IF_FALSE - } // bpp_gen() - - // efficient multiexponentiation (naive stub implementation atm, TODO) template bool multiexp_and_check_being_zero(const scalar_vec_t& g_scalars, const scalar_vec_t& h_scalars, const point_t& summand) { - CHECK_AND_ASSERT_MES(g_scalars.size() < c_bpp_mn_max, false, "g_scalars oversized"); - CHECK_AND_ASSERT_MES(h_scalars.size() < c_bpp_mn_max, false, "h_scalars oversized"); + CHECK_AND_ASSERT_MES(g_scalars.size() < CT::c_bpp_mn_max, false, "g_scalars oversized"); + CHECK_AND_ASSERT_MES(h_scalars.size() < CT::c_bpp_mn_max, false, "h_scalars oversized"); point_t result = summand; @@ -452,372 +145,6 @@ namespace crypto } - struct bpp_sig_commit_ref_t - { - bpp_sig_commit_ref_t(const bpp_signature& sig, const std::vector& commitments) - : sig(sig) - , commitments(commitments) - {} - const bpp_signature& sig; - const std::vector& commitments; - }; - - - template - bool bpp_verify(const std::vector& sigs, uint8_t* p_err = nullptr) - { -#define CHECK_AND_FAIL_WITH_ERROR_IF_FALSE(cond, err_code) \ - if (!(cond)) { LOG_PRINT_RED("bpp_verify: \"" << #cond << "\" is false at " << LOCATION_SS << ENDL << "error code = " << err_code, LOG_LEVEL_3); \ - if (p_err) { *p_err = err_code; } return false; } - - DBG_PRINT(ENDL << " . . . . bpp_verify() . . . . "); - - const size_t kn = sigs.size(); - CHECK_AND_FAIL_WITH_ERROR_IF_FALSE(kn > 0, 1); - - struct intermediate_element_t - { - scalar_t y; - scalar_t z; - scalar_t z_sq; - scalar_vec_t e; - scalar_vec_t e_sq; - scalar_t e_final; - scalar_t e_final_sq; - size_t inv_e_offset; // offset in batch_for_inverse - size_t inv_y_offset; // offset in batch_for_inverse - size_t c_bpp_log2_m; - size_t c_bpp_m; - size_t c_bpp_mn; - point_t A; - point_t A0; - point_t B; - std::vector L; - std::vector R; - }; - std::vector interms(kn); - - size_t c_bpp_log2_m_max = 0; - for (size_t k = 0; k < kn; ++k) - { - const bpp_sig_commit_ref_t& bsc = sigs[k]; - const bpp_signature& sig = bsc.sig; - CHECK_AND_FAIL_WITH_ERROR_IF_FALSE(bsc.commitments.size() > 0, 2); - CHECK_AND_FAIL_WITH_ERROR_IF_FALSE(sig.L.size() > 0 && sig.L.size() == sig.R.size(), 3); - CHECK_AND_FAIL_WITH_ERROR_IF_FALSE(sig.r.is_reduced() && sig.s.is_reduced() && sig.delta.is_reduced(), 4); - - intermediate_element_t& interm = interms[k]; - interm.c_bpp_log2_m = calc_exp_power_of_2_upper_bound(bsc.commitments.size()); - if (c_bpp_log2_m_max < interm.c_bpp_log2_m) - c_bpp_log2_m_max = interm.c_bpp_log2_m; - - CHECK_AND_FAIL_WITH_ERROR_IF_FALSE(sig.L.size() == interm.c_bpp_log2_m + c_bpp_log2_n, 5); - - interm.c_bpp_m = 1ull << interm.c_bpp_log2_m; - interm.c_bpp_mn = interm.c_bpp_m * c_bpp_n; - - CHECK_AND_FAIL_WITH_ERROR_IF_FALSE(interm.A0.from_public_key(sig.A0), 6); - CHECK_AND_FAIL_WITH_ERROR_IF_FALSE(interm.A.from_public_key(sig.A), 7); - CHECK_AND_FAIL_WITH_ERROR_IF_FALSE(interm.B.from_public_key(sig.B), 8); - interm.L.resize(sig.L.size()); - interm.R.resize(sig.R.size()); - for (size_t i = 0; i < interm.L.size(); ++i) - { - CHECK_AND_FAIL_WITH_ERROR_IF_FALSE(interm.L[i].from_public_key(sig.L[i]), 9); - CHECK_AND_FAIL_WITH_ERROR_IF_FALSE(interm.R[i].from_public_key(sig.R[i]), 10); - } - } - const size_t c_bpp_m_max = 1ull << c_bpp_log2_m_max; - const size_t c_bpp_mn_max = c_bpp_m_max * c_bpp_n; - const size_t c_bpp_LR_size_max = c_bpp_log2_m_max + c_bpp_log2_n; - - - // - // prepare stuff - // - /* - std::vector g(c_bpp_mn_max), h(c_bpp_mn_max); - for (size_t i = 0; i < c_bpp_mn_max; ++i) - { - g[i] = CT::get_generator(false, i); - h[i] = CT::get_generator(true, i); - } - */ - - scalar_vec_t batch_for_inverse; - batch_for_inverse.reserve(kn + kn * c_bpp_LR_size_max); - - - for (size_t k = 0; k < kn; ++k) - { - DBG_PRINT(ENDL << "SIG #" << k); - const bpp_sig_commit_ref_t& bsc = sigs[k]; - const bpp_signature& sig = bsc.sig; - intermediate_element_t& interm = interms[k]; - - // restore y and z - // using e as Fiat-Shamir transcript - scalar_t e = CT::get_initial_transcript(); - DBG_PRINT("initial transcript: " << e); - hash_helper_t::hs_t hsc; - CT::update_transcript(hsc, e, bsc.commitments); - // calculate scalar challenges y and z - hsc.add_scalar(e); - hsc.add_pub_key(sig.A0); - hsc.assign_calc_hash(interm.y); - interm.z = hash_helper_t::hs(interm.y); - interm.z_sq = interm.z * interm.z; - DBG_VAL_PRINT(interm.y); - DBG_VAL_PRINT(interm.z); - e = interm.z; // transcript for further steps - - interm.inv_y_offset = batch_for_inverse.size(); - batch_for_inverse.push_back(interm.y); - interm.inv_e_offset = batch_for_inverse.size(); - - interm.e.resize(sig.L.size()); - interm.e_sq.resize(sig.L.size()); - - for (size_t i = 0; i < sig.L.size(); ++i) - { - hsc.add_scalar(e); - hsc.add_pub_key(sig.L[i]); - hsc.add_pub_key(sig.R[i]); - hsc.assign_calc_hash(e); - interm.e[i] = e; - interm.e_sq[i] = e * e; - DBG_PRINT("e[" << i << "]: " << e); - batch_for_inverse.push_back(e); - } - - hsc.add_scalar(e); - hsc.add_pub_key(sig.A); - hsc.add_pub_key(sig.B); - hsc.assign_calc_hash(interm.e_final); - interm.e_final_sq = interm.e_final * interm.e_final; - DBG_VAL_PRINT(interm.e_final); - } - - batch_for_inverse.invert(); - - // Notation: - // 1_vec ^ n = (1, 1, 1, ..., 1) - // 2_vec ^ n = (2^0, 2^1, 2^2, ..., 2^(n-1)) - // -1_vec ^ n = ((-1)^0, (-1)^1, (-1)^2, ... (-1)^(n-1)) = (1, -1, 1, -1, ...) - // y<^n = (y^n, y^(n-1), ..., y^1) - // y>^n = (y^1, y^2, ..., y^n) - - // from page 13, Fig 1: - // Verifier outputs Accept IFF the following equality holds (single proof): - // P^e^2 * A^e * B == g ^ (r' e) * h ^ (s' e) * G ^ (r' y s') * H ^ delta' - // (where g and h are calculated in each round) - // The same equation in additive notation: - // e^2 * P + e * A + B == (r' * e) * g + (s' * e) * h + (r' y s') * G + delta' * H - // <=> - // (r' * e) * g + (s' * e) * h + (r' y s') * G + delta' * H - e^2 * P - e * A - B == 0 (*) - // where A, B, r', s', delta' is taken from the signature - // and P_{k+1} = e^2 * L_k + P_k + e^-2 * R_k for all rounds - // - // from page 18, Fig 3: - // P and V computes: - // A_hat = A0 + (- 1^(mn) * z) * g + (d o y<^(mn) + 1^(mn) * z) * h + - // + y^(mn+1) * (SUM{j=1..m} z^(2j) * V_j) + - // + (z*SUM(y^>mn) - z*y^(mn+1)*SUM(d) - z^2 * SUM(y^>mn)) * G - // (calculated once) - // - // As suggested in Section 6.1 "Practical Optimizations": - // 1) g and h exponentianions can be optimized in order not to be calculated at each round as the following (page 20): - // - // (r' * e * s_vec) * g + (s' * e * s'_vec) * h + (r' y s') * G + delta' * H - - // - e^2 * A_hat - // - SUM{j=1..log(n)}(e_final^2 * e_j^2 * L_j + e_final^2 * e_j^-2 * R_j) - // - e * A - B = 0 (**) - // - // where: - // g, h - vector of fixed generators - // s_vec_i = y^(1-i) * PROD{j=1..log(n)}(e_j ^ b(i,j)) - // s'_vec_i = PROD{j=1..log(n)}(e_j ^ -b(i,j)) - // b(i, j) = { 2 * ((1<<(j-1)) & (i-1)) - 1) (counting both from 1) (page 20) - // b(i, j) = { 2 * ((1< - - // (r' * e * s_vec) * g + (s' * e * s'_vec) * h + (r' y s') * G + delta' * H - - // - e^2 * (A0 + (- 1^(mn) * z) * g + (d o y<^(mn) + 1^(mn) * z) * h + - // + y^(mn+1) * (SUM{j=1..m} z^(2j) * V_j) + - // + (z*SUM(y^>mn) - z*y^(mn+1)*SUM(d) - z^2 * SUM(y^>mn)) * G - // ) - // - SUM{j=1..log(n)}(e_final^2 * e_j^2 * L_j + e_final^2 * e_j^-2 * R_j) - // - e * A - B = 0 - - // => - - // (for single signature) - // - // (r' * e * s_vec - e^2 * (- 1_vec^(mn) * z)) * g | these are - // + (s' * e * s'_vec - e^2 * (d o y<^(mn) + 1_vec^(mn) * z)) * h | fixed generators - // + (r' y s' - e^2 * ((z - z^2)*SUM(y^>mn) - z*y^(mn+1)*SUM(d)) * G | across all - // + delta' * H | the signatures - // - // - e^2 * A0 - // - e^2 * y^(mn+1) * (SUM{j=1..m} z^(2j) * V_j)) - // - e^2 * SUM{j=1..log(n)}(e_j^2 * L_j + e_j^-2 * R_j) - // - e * A - B = 0 (***) - // - // All (***) will be muptiplied by random weightning factor and then summed up. - - // Calculate cummulative sclalar multiplicand for fixed generators across all the sigs. - scalar_vec_t g_scalars; - g_scalars.resize(c_bpp_mn_max, 0); - scalar_vec_t h_scalars; - h_scalars.resize(c_bpp_mn_max, 0); - scalar_t G_scalar = 0; - scalar_t H_scalar = 0; - point_t summand = c_point_0; - - for (size_t k = 0; k < kn; ++k) - { - DBG_PRINT(ENDL << "SIG #" << k); - const bpp_sig_commit_ref_t& bsc = sigs[k]; - const bpp_signature& sig = bsc.sig; - intermediate_element_t& interm = interms[k]; - - // random weightning factor for speed-optimized batch verification (preprint page 20) - const scalar_t rwf = scalar_t::random(); - DBG_PRINT("rwf: " << rwf); - - // prepare d vector (see also d structure description in proof function) - scalar_mat_t d(interm.c_bpp_mn); - d(0, 0) = interm.z_sq; - // first row - for (size_t i = 1; i < interm.c_bpp_m; ++i) - d(i, 0) = d(i - 1, 0) * interm.z_sq; - // all rows - for (size_t j = 1; j < c_bpp_n; ++j) - for (size_t i = 0; i < interm.c_bpp_m; ++i) - d(i, j) = d(i, j - 1) + d(i, j - 1); - // sum(d) (see also note in proof function for this) - static const scalar_t c_scalar_2_power_n_minus_1 = { 0xffffffffffffffff, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000 }; - const scalar_t sum_d = c_scalar_2_power_n_minus_1 * sum_of_powers(interm.z_sq, interm.c_bpp_log2_m); - - DBG_PRINT("Hs(d): " << d.calc_hs()); - DBG_PRINT("sum(d): " << sum_d); - - const scalar_t& y_inv = batch_for_inverse[interm.inv_y_offset]; - auto get_e_inv = [&](size_t i) { return batch_for_inverse[interm.inv_e_offset + i]; }; // i belongs to [0; L.size()-1] - - // prepare s_vec (unlike the paper here we moved y-component out of s_vec for convenience, so s_vec'[x] = s_vec[~x & (MN-1)]) - // complexity (sc_mul's): MN+2*log2(MN)-2 - // the idea is the following: - // s_vec[00000b] = ... * (e_4)^-1 * (e_3)^-1 * (e_2)^-1 * (e_1)^-1 * (e_0)^-1 - // s_vec[00101b] = ... * (e_4)^-1 * (e_3)^-1 * (e_2)^+1 * (e_1)^-1 * (e_0)^+1 - const size_t log2_mn = sig.L.size(); // at the beginning we made sure that sig.L.size() == c_bpp_log2_m + c_bpp_log2_n - scalar_vec_t s_vec(interm.c_bpp_mn); - s_vec[0] = get_e_inv(0); - for (size_t i = 1; i < log2_mn; ++i) - s_vec[0] *= get_e_inv(i); // s_vec[0] = (e_0)^-1 * (e_1)^-1 * .. (e_{log2_mn-1})^-1 - DBG_PRINT("[0] " << s_vec[0]); - for (size_t i = 1; i < interm.c_bpp_mn; ++i) - { - size_t base_el_index = i & (i - 1); // base element index: 0, 0, 2, 0, 4, 4, 6, 0, 8, 8, 10... base element differs in one bit (0) from the current one (1) - size_t bit_index = log2_mn - calc_lsb_32((uint32_t)i) - 1; // the bit index where current element has the difference with the base - s_vec[i] = s_vec[base_el_index] * interm.e_sq[bit_index]; // (e_j)^-1 * (e_j)^2 = (e_j)^+1 - DBG_PRINT("[" << i << "] " << " " << base_el_index << ", " << bit_index << " : " << s_vec[i]); - } - - // prepare y_inv vector - scalar_vec_t y_inverse_powers(interm.c_bpp_mn); - y_inverse_powers[0] = 1; - for (size_t i = 1; i < interm.c_bpp_mn; ++i) - y_inverse_powers[i] = y_inverse_powers[i - 1] * y_inv; - - // y^(mn+1) - scalar_t y_power_mnp1 = interm.y; - for (size_t i = 0; i < log2_mn; ++i) - y_power_mnp1 *= y_power_mnp1; - y_power_mnp1 *= interm.y; - DBG_VAL_PRINT(y_power_mnp1); - - // now calculate all multiplicands for common generators - - // g vector multiplicands: - // rwf * (r' * e * (1, y^-1, y^-2, ...) o s_vec + e^2 * z) = - // rwf * r' * e * ((1, y^-1, ...) o s_vec) + rwf * e^2 * z * (1, 1, ...) - scalar_t rwf_e_sq_z = rwf * interm.e_final_sq * interm.z; - scalar_t rwf_r_e = rwf * interm.e_final * sig.r; - for (size_t i = 0; i < interm.c_bpp_mn; ++i) - g_scalars[i] += rwf_r_e * y_inverse_powers[i] * s_vec[i] + rwf_e_sq_z; - - DBG_PRINT("Hs(g_scalars): " << g_scalars.calc_hs()); - - // h vector multiplicands: - // rwf * (s' * e * s'_vec - e^2 * (d o y<^(mn) + 1_vec^(mn) * z)) - // rwf * s' * e * s'_vec - rwf * e^2 * z * (1, 1...) - rwf * e^2 * (d o y<^(mn)) - //scalar_t rwf_e_sq_z = rwf * interm.e_final_sq * interm.z; - scalar_t rwf_s_e = rwf * sig.s * interm.e_final; - scalar_t rwf_e_sq_y = rwf * interm.e_final_sq * interm.y; - for (size_t i = interm.c_bpp_mn - 1; i != SIZE_MAX; --i) - { - h_scalars[i] += rwf_s_e * s_vec[interm.c_bpp_mn - 1 - i] - rwf_e_sq_z - rwf_e_sq_y * d[i]; - rwf_e_sq_y *= interm.y; - } - - DBG_PRINT("Hs(h_scalars): " << h_scalars.calc_hs()); - - // G point multiplicands: - // rwf * (r' y s' - e ^ 2 * ((z - z ^ 2)*SUM(y^>mn) - z * y^(mn+1) * SUM(d)) = - // = rwf * r' y s' - rwf * e^2 * (z - z ^ 2)*SUM(y^>mn) + rwf * e^2 * z * y^(mn+1) * SUM(d) - G_scalar += rwf * sig.r * interm.y * sig.s + rwf_e_sq_y * sum_d * interm.z; - G_scalar -= rwf * interm.e_final_sq * (interm.z - interm.z_sq) * sum_of_powers(interm.y, log2_mn); - DBG_PRINT("sum_y: " << sum_of_powers(interm.y, log2_mn)); - DBG_PRINT("G_scalar: " << G_scalar); - - // H point multiplicands: - // rwf * delta - H_scalar += rwf * sig.delta; - DBG_PRINT("H_scalar: " << H_scalar); - - // uncommon generators' multiplicands - point_t summand_8 = c_point_0; // this summand to be multiplied by 8 before adding to the main summand - // - rwf * e^2 * A0 - summand_8 -= rwf * interm.e_final_sq * interm.A0; - DBG_PRINT("A0_scalar: " << c_scalar_Lm1 * interm.e_final_sq * rwf); - - // - rwf * e^2 * y^(mn+1) * (SUM{j=1..m} (z^2)^j * V_j)) - scalar_t e_sq_y_mn1_z_sq_power = rwf * interm.e_final_sq * y_power_mnp1; - for (size_t j = 0; j < bsc.commitments.size(); ++j) - { - e_sq_y_mn1_z_sq_power *= interm.z_sq; - summand_8 -= e_sq_y_mn1_z_sq_power * bsc.commitments[j]; - DBG_PRINT("V_scalar[" << j << "]: " << c_scalar_Lm1 * e_sq_y_mn1_z_sq_power); - } - - // - rwf * e^2 * SUM{j=1..log(n)}(e_j^2 * L_j + e_j^-2 * R_j) - scalar_t rwf_e_sq = rwf * interm.e_final_sq; - for (size_t j = 0; j < log2_mn; ++j) - { - summand_8 -= rwf_e_sq * (interm.e_sq[j] * interm.L[j] + get_e_inv(j) * get_e_inv(j) * interm.R[j]); - DBG_PRINT("L_scalar[" << j << "]: " << c_scalar_Lm1 * rwf_e_sq * interm.e_sq[j]); - DBG_PRINT("R_scalar[" << j << "]: " << c_scalar_Lm1 * rwf_e_sq * get_e_inv(j) * get_e_inv(j)); - } - - // - rwf * e * A - rwf * B = 0 - summand_8 -= rwf * interm.e_final * interm.A + rwf * interm.B; - DBG_PRINT("A_scalar: " << c_scalar_Lm1 * rwf * interm.e_final); - DBG_PRINT("B_scalar: " << c_scalar_Lm1 * rwf); - - summand_8.modify_mul8(); - summand += summand_8; - } - - point_t GH_exponents = c_point_0; - CT::calc_pedersen_commitment(G_scalar, H_scalar, GH_exponents); - bool result = multiexp_and_check_being_zero(g_scalars, h_scalars, summand + GH_exponents); - if (result) - DBG_PRINT(ENDL << " . . . . bpp_verify() -- SUCCEEDED!!!" << ENDL); - return result; -#undef CHECK_AND_FAIL_WITH_ERROR_IF_FALSE - } - } // namespace crypto + +#include "range_proof_bpp.h" diff --git a/tests/functional_tests/crypto_tests.cpp b/tests/functional_tests/crypto_tests.cpp index 19c922e2..68350097 100644 --- a/tests/functional_tests/crypto_tests.cpp +++ b/tests/functional_tests/crypto_tests.cpp @@ -487,6 +487,7 @@ struct test_keeper_t //////////////////////////////////////////////////////////////////////////////// #include "L2S.h" +#include "crypto_tests_range_proofs.h" //////////////////////////////////////////////////////////////////////////////// @@ -1843,6 +1844,7 @@ TEST(crypto, sc_get_bit) return true; } + // // test's runner // diff --git a/tests/functional_tests/crypto_tests_range_proofs.h b/tests/functional_tests/crypto_tests_range_proofs.h new file mode 100644 index 00000000..94f4db0b --- /dev/null +++ b/tests/functional_tests/crypto_tests_range_proofs.h @@ -0,0 +1,182 @@ +// Copyright (c) 2021 Zano Project (https://zano.org/) +// Copyright (c) 2021 sowle (val@zano.org, crypto.sowle@gmail.com) +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. +#pragma once + +// calc weighted inner pruduct of av and bv w.r.t. Vandermonde vector (y, y^2, y^3, ..., y^n) +// = (<> -- standard inner product, o - componen-wise) +// s.a. BP+ paper, pages 3-4 +bool wip_vandermonde(const scalar_vec_t& av, const scalar_vec_t& bv, const scalar_t& y, scalar_t& result) +{ + result = 0; + size_t n = av.size(); + if (n != bv.size()) + return false; + + scalar_t y_powered = 1; + for (size_t i = 0; i < n; ++i) + { + y_powered *= y; + result.assign_muladd(av[i] * bv[i], y_powered, result); // result.a += av[i] * bv[i] * y_powered; + } + + return true; +} + + +static_assert(constexpr_floor_log2(0) == 0, ""); +static_assert(constexpr_floor_log2(1) == 0, ""); +static_assert(constexpr_floor_log2(2) == 1, ""); +static_assert(constexpr_floor_log2(3) == 1, ""); +static_assert(constexpr_floor_log2(4) == 2, ""); +static_assert(constexpr_floor_log2(5) == 2, ""); +static_assert(constexpr_floor_log2(64) == 6, ""); +static_assert(constexpr_floor_log2(100) == 6, ""); +static_assert(constexpr_floor_log2(100000000) == 26, ""); +static_assert(constexpr_floor_log2(0x7fffffffffffffff) == 62, ""); +static_assert(constexpr_floor_log2(SIZE_MAX) == 63, ""); + +static_assert(constexpr_ceil_log2(0) == 0, ""); +static_assert(constexpr_ceil_log2(1) == 0, ""); +static_assert(constexpr_ceil_log2(2) == 1, ""); +static_assert(constexpr_ceil_log2(3) == 2, ""); +static_assert(constexpr_ceil_log2(4) == 2, ""); +static_assert(constexpr_ceil_log2(5) == 3, ""); +static_assert(constexpr_ceil_log2(64) == 6, ""); +static_assert(constexpr_ceil_log2(100) == 7, ""); +static_assert(constexpr_ceil_log2(100000000) == 27, ""); +static_assert(constexpr_ceil_log2(0x7fffffffffffffff) == 63, ""); +static_assert(constexpr_ceil_log2(SIZE_MAX) == 64, ""); + + +TEST(bpp, basics) +{ + /* + srand(0); + for (size_t i = 0; i < 10; ++i) + std::cout << scalar_t::random().to_string_as_secret_key() << ENDL; + */ + + point_t H = hash_helper_t::hp(c_point_G); + ASSERT_EQ(H, c_point_H); + std::string h2_hash_str("h2_generator"); + point_t H2 = hash_helper_t::hp(h2_hash_str.c_str(), h2_hash_str.size()); + ASSERT_EQ(H2, c_point_H2); + LOG_PRINT_L0("c_point_0 = " << c_point_0 << " = { " << c_point_0.to_hex_comma_separated_uint64_str() << " }"); + LOG_PRINT_L0("Zano G = " << c_point_G << " = { " << c_point_G.to_hex_comma_separated_bytes_str() << " }"); + LOG_PRINT_L0("Zano H = " << H << " = { " << H.to_hex_comma_separated_uint64_str() << " }"); + LOG_PRINT_L0("Zano H2 = " << H2 << " = { " << H2.to_hex_comma_separated_uint64_str() << " }"); + + scalar_vec_t values = { 5 }; + scalar_vec_t masks = { 0 }; + bpp_signature bpp_sig; + std::vector commitments; + uint8_t err = 0; + + bool r = bpp_gen>(values, masks, bpp_sig, commitments, &err); + + ASSERT_TRUE(r); + + return true; +} + + +TEST(bpp, two) +{ + std::vector signatures_vector; + signatures_vector.reserve(10); + std::vector> commitments_vector; + commitments_vector.reserve(10); + + std::vector sigs; + uint8_t err = 0; + bool r = false; + + { + signatures_vector.resize(signatures_vector.size() + 1); + bpp_signature &bpp_sig = signatures_vector.back(); + commitments_vector.resize(commitments_vector.size() + 1); + std::vector& commitments = commitments_vector.back(); + + scalar_vec_t values = { 5 }; + scalar_vec_t masks = { scalar_t(77 + 256 * 77) }; + + r = bpp_gen>(values, masks, bpp_sig, commitments, &err); + ASSERT_TRUE(r); + + sigs.emplace_back(bpp_sig, commitments); + } + + { + signatures_vector.resize(signatures_vector.size() + 1); + bpp_signature &bpp_sig = signatures_vector.back(); + commitments_vector.resize(commitments_vector.size() + 1); + std::vector& commitments = commitments_vector.back(); + + scalar_vec_t values = { 5, 700, 8 }; + scalar_vec_t masks = { scalar_t(77 + 256 * 77), scalar_t(255), scalar_t(17) }; + + r = bpp_gen>(values, masks, bpp_sig, commitments, &err); + ASSERT_TRUE(r); + + sigs.emplace_back(bpp_sig, commitments); + } + + r = bpp_verify>(sigs, &err); + ASSERT_TRUE(r); + + + return true; +} + + +TEST(bpp, power_256) +{ + // make sure the BPP implementation supports values up to 2^256 (Zarcanum needs 2^170 since b_a < z * 2^64, where z = 2^106, s.a. Zarcanum preprint, page 21) + std::vector signatures_vector; + signatures_vector.reserve(10); + std::vector> commitments_vector; + commitments_vector.reserve(10); + + std::vector sig_ñommit_refs; + uint8_t err = 0; + bool r = false; + + { + signatures_vector.resize(signatures_vector.size() + 1); + bpp_signature &bpp_sig = signatures_vector.back(); + commitments_vector.resize(commitments_vector.size() + 1); + std::vector& commitments = commitments_vector.back(); + + scalar_vec_t values = { 5 }; + scalar_vec_t masks = { scalar_t(77 + 256 * 77) }; + + r = bpp_gen>(values, masks, bpp_sig, commitments, &err); + ASSERT_TRUE(r); + + sig_ñommit_refs.emplace_back(bpp_sig, commitments); + } + + { + signatures_vector.resize(signatures_vector.size() + 1); + bpp_signature &bpp_sig = signatures_vector.back(); + commitments_vector.resize(commitments_vector.size() + 1); + std::vector& commitments = commitments_vector.back(); + + scalar_vec_t values = { 5, 700, 8 }; + scalar_vec_t masks = { scalar_t(77 + 256 * 77), scalar_t(255), scalar_t(17) }; + + r = bpp_gen>(values, masks, bpp_sig, commitments, &err); + ASSERT_TRUE(r); + + sig_ñommit_refs.emplace_back(bpp_sig, commitments); + } + + r = bpp_verify>(sig_ñommit_refs, &err); + ASSERT_TRUE(r); + + + return true; +} + From 218c6a38cb58d63f0beecd158bf2d215649de07c Mon Sep 17 00:00:00 2001 From: sowle Date: Mon, 11 Apr 2022 20:43:43 +0200 Subject: [PATCH 09/15] crypto: Bulletproofs+ with double-blinded commitments extension implemented (nicknamed as bppe), basic tests added --- src/crypto/range_proof_bppe.h | 719 ++++++++++++++++++ src/crypto/range_proofs.h | 1 + .../crypto_tests_range_proofs.h | 79 ++ 3 files changed, 799 insertions(+) create mode 100644 src/crypto/range_proof_bppe.h diff --git a/src/crypto/range_proof_bppe.h b/src/crypto/range_proof_bppe.h new file mode 100644 index 00000000..83fc83c2 --- /dev/null +++ b/src/crypto/range_proof_bppe.h @@ -0,0 +1,719 @@ +// Copyright (c) 2022 Zano Project (https://zano.org/) +// Copyright (c) 2022 sowle (val@zano.org, crypto.sowle@gmail.com) +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. +#pragma once + +// +// This file contains the implementation of range proof protocol. +// Namely, Bulletproofs+ https://eprint.iacr.org/2020/735 +// Double-blinded commitments extension implemented as in Appendix D in the Zarcanum whitepaper: https://eprint.iacr.org/2021/1478 + +namespace crypto +{ + struct bppe_signature + { + std::vector L; // size = log_2(m * n) + std::vector R; + public_key A0; + public_key A; + public_key B; + scalar_t r; + scalar_t s; + scalar_t delta_1; + scalar_t delta_2; + }; + +#define DBG_VAL_PRINT(x) std::cout << #x ": " << x << ENDL +#define DBG_PRINT(x) std::cout << x << ENDL + + template + bool bppe_gen(const scalar_vec_t& values, const scalar_vec_t& masks, const scalar_vec_t& masks2, bppe_signature& sig, std::vector& commitments, uint8_t* p_err = nullptr) + { +#define CHECK_AND_FAIL_WITH_ERROR_IF_FALSE(cond, err_code) \ + if (!(cond)) { LOG_PRINT_RED("bppe_gen: \"" << #cond << "\" is false at " << LOCATION_SS << ENDL << "error code = " << err_code, LOG_LEVEL_3); \ + if (p_err) { *p_err = err_code; } return false; } + + CHECK_AND_FAIL_WITH_ERROR_IF_FALSE(values.size() > 0 && values.size() <= CT::c_bpp_values_max && values.size() == masks.size() && masks.size() == masks2.size(), 1); + CHECK_AND_FAIL_WITH_ERROR_IF_FALSE(masks.is_reduced() && masks2.is_reduced(), 3); + + const size_t c_bpp_log2_m = constexpr_ceil_log2(values.size()); + const size_t c_bpp_m = 1ull << c_bpp_log2_m; + const size_t c_bpp_mn = c_bpp_m * CT::c_bpp_n; + const size_t c_bpp_log2_mn = c_bpp_log2_m + CT::c_bpp_log2_n; + + // pre-multiply all output points by c_scalar_1div8 + // in order to enforce these points to be in the prime-order subgroup (after mul by 8 in bpp_verify()) + + // calc commitments vector as commitments[i] = 1/8 * values[i] * G + 1/8 * masks[i] * H + 1/8 * masks2[i] * H2 + commitments.resize(values.size()); + for (size_t i = 0; i < values.size(); ++i) + CT::calc_pedersen_commitment_2(values[i] * c_scalar_1div8, masks[i] * c_scalar_1div8, masks2[i] * c_scalar_1div8, commitments[i]); + + + // s.a. BP+ paper, page 15, eq. 11 + // decompose v into aL and aR: + // v = aL o (1, 2, 2^2, ..., 2^n-1), o - component-wise product aka Hadamard product + // aR = aL - (1, 1, ... 1) + // aR o aL = 0 + + // aLs = (aL_0, aL_1, ..., aL_m-1) -- `bit` matrix of c_bpp_m x c_bpp_n, each element is a scalar + + scalar_mat_t aLs(c_bpp_mn), aRs(c_bpp_mn); + aLs.zero(); + aRs.zero(); + // m >= values.size, first set up [0..values.size-1], then -- [values.size..m-1] (padding area) + for (size_t i = 0; i < values.size(); ++i) + { + const scalar_t& v = values[i]; + for (size_t j = 0; j < CT::c_bpp_n; ++j) + { + if (v.get_bit(j)) + aLs(i, j) = c_scalar_1; // aL = 1, aR = 0 + else + aRs(i, j) = c_scalar_Lm1; // aL = 0, aR = -1 + } + } + + for (size_t i = values.size(); i < c_bpp_m; ++i) + for (size_t j = 0; j < CT::c_bpp_n; ++j) + aRs(i, j) = c_scalar_Lm1; // aL = 0, aR = -1 + + + // using e as Fiat-Shamir transcript + scalar_t e = CT::get_initial_transcript(); + DBG_PRINT("initial transcript: " << e); + + hash_helper_t::hs_t hsc; + CT::update_transcript(hsc, e, commitments); + + // Zarcanum paper, page 33, Fig. D.3: The prover chooses alpha_1, alpha_2 and computes A = g^aL h^aR h_1^alpha_1 h_2^alpha_2 + // so we calculate A0 = alpha_1 * H + alpha_2 * H_2 + SUM(aL_i * G_i) + SUM(aR_i * H_i) + + scalar_t alpha_1 = scalar_t::random(), alpha_2 = scalar_t::random(); + point_t A0 = alpha_1 * CT::bpp_H + alpha_2 * CT::bpp_H2; + + for (size_t i = 0; i < c_bpp_mn; ++i) + A0 += aLs[i] * CT::get_generator(false, i) + aRs[i] * CT::get_generator(true, i); + + // part of 1/8 defense scheme + A0 *= c_scalar_1div8; + A0.to_public_key(sig.A0); + + DBG_VAL_PRINT(alpha_1); + DBG_VAL_PRINT(alpha_2); + DBG_VAL_PRINT(A0); + + // calculate scalar challenges y and z + hsc.add_scalar(e); + hsc.add_pub_key(sig.A0); + scalar_t y = hsc.calc_hash(); + scalar_t z = hash_helper_t::hs(y); + e = z; // transcript for further steps + DBG_VAL_PRINT(y); + DBG_VAL_PRINT(z); + + // Computing vector d for aggregated version of the protocol (BP+ paper, page 17) + // (note: elements is stored column-by-column in memory) + // d = | 1 * z^(2*1), 1 * z^(2*2), 1 * z^(2*3), ..., 1 * z^(2*m) | + // | 2 * z^(2*1), 2 * z^(2*2), 2 * z^(2*3), ..., 2 * z^(2*m) | + // | 4 * z^(2*1), 4 * z^(2*2), 4 * z^(2*3), ..., 4 * z^(2*m) | + // | ....................................................................................... | + // | 2^(n-1) * z^(2*1), 2^(n-1) * z^(2*2), 2^(n-1) * z^(2*3), ..., 2^(n-1) * z^(2*m)) | + // Note: sum(d_i) = (2^n - 1) * ((z^2)^1 + (z^2)^2 + ... (z^2)^m)) = (2^n-1) * sum_of_powers(x^2, log(m)) + + scalar_t z_sq = z * z; + scalar_mat_t d(c_bpp_mn); + d(0, 0) = z_sq; + // first row + for (size_t i = 1; i < c_bpp_m; ++i) + d(i, 0) = d(i - 1, 0) * z_sq; + // all rows + for (size_t j = 1; j < CT::c_bpp_n; ++j) + for (size_t i = 0; i < c_bpp_m; ++i) + d(i, j) = d(i, j - 1) + d(i, j - 1); + + DBG_PRINT("Hs(d): " << d.calc_hs()); + + // calculate extended Vandermonde vector y = (1, y, y^2, ..., y^(mn+1)) (BP+ paper, page 18, Fig. 3) + // (calculate two more elements (1 and y^(mn+1)) for convenience) + scalar_vec_t y_powers(c_bpp_mn + 2); + y_powers[0] = 1; + for (size_t i = 1; i <= c_bpp_mn + 1; ++i) + y_powers[i] = y_powers[i - 1] * y; + + const scalar_t& y_mn_p1 = y_powers[c_bpp_mn + 1]; + + DBG_PRINT("Hs(y_powers): " << y_powers.calc_hs()); + + // aL_hat = aL - 1*z + scalar_vec_t aLs_hat = aLs - z; + // aL_hat = aR + d o y^leftarr + 1*z where y^leftarr = (y^n, y^(n-1), ..., y) (BP+ paper, page 18, Fig. 3) + scalar_vec_t aRs_hat = aRs + z; + for (size_t i = 0; i < c_bpp_mn; ++i) + aRs_hat[i] += d[i] * y_powers[c_bpp_mn - i]; + + DBG_PRINT("Hs(aLs_hat): " << aLs_hat.calc_hs()); + DBG_PRINT("Hs(aRs_hat): " << aRs_hat.calc_hs()); + + // calculate alpha_hat + // alpha_hat_1 = alpha_1 + SUM(z^(2j) * gamma_1,j * y^(mn+1)) for j = 1..m + // alpha_hat_2 = alpha_2 + SUM(z^(2j) * gamma_2,j * y^(mn+1)) for j = 1..m + // i.e. \hat{\alpha} = \alpha + y^{m n+1} \sum_{j = 1}^{m} z^{2j} \gamma_j + scalar_t alpha_hat_1 = 0, alpha_hat_2 = 0; + for (size_t i = 0; i < masks.size(); ++i) + { + alpha_hat_1 += d(i, 0) * masks[i]; + alpha_hat_2 += d(i, 0) * masks2[i]; + } + alpha_hat_1 = alpha_1 + y_mn_p1 * alpha_hat_1; + alpha_hat_2 = alpha_2 + y_mn_p1 * alpha_hat_2; + + DBG_VAL_PRINT(alpha_hat_1); + DBG_VAL_PRINT(alpha_hat_2); + + // calculate y^-1, y^-2, ... + const scalar_t y_inverse = y.reciprocal(); + scalar_vec_t y_inverse_powers(c_bpp_mn / 2 + 1); // the greatest power we need is c_bpp_mn/2 (at the first reduction round) + y_inverse_powers[0] = 1; + for (size_t i = 1, size = y_inverse_powers.size(); i < size; ++i) + y_inverse_powers[i] = y_inverse_powers[i - 1] * y_inverse; + + // prepare generator's vector + std::vector g(c_bpp_mn), h(c_bpp_mn); + for (size_t i = 0; i < c_bpp_mn; ++i) + { + g[i] = CT::get_generator(false, i); + h[i] = CT::get_generator(true, i); + } + + // WIP zk-argument called with zk-WIP(g, h, G, H, H2, A_hat, aL_hat, aR_hat, alpha_hat_1, alpha_hat_2) + + scalar_vec_t& a = aLs_hat; + scalar_vec_t& b = aRs_hat; + + sig.L.resize(c_bpp_log2_mn); + sig.R.resize(c_bpp_log2_mn); + + // zk-WIP reduction rounds (s.a. Zarcanum preprint page 24 Fig. D.1) + for (size_t n = c_bpp_mn / 2, ni = 0; n >= 1; n /= 2, ++ni) + { + DBG_PRINT(ENDL << "#" << ni); + + // zk-WIP(g, h, G, H, H2, P, a, b, alpha_1, alpha_2) + + scalar_t dL = scalar_t::random(), dL2 = scalar_t::random(); + DBG_VAL_PRINT(dL); DBG_VAL_PRINT(dL2); + scalar_t dR = scalar_t::random(), dR2 = scalar_t::random(); + DBG_VAL_PRINT(dR); DBG_VAL_PRINT(dR2); + + // a = (a1, a2), b = (b1, b2) -- vectors of scalars + // cL = -- scalar + scalar_t cL = 0; + for (size_t i = 0; i < n; ++i) + cL += a[i] * y_powers[i + 1] * b[n + i]; + + DBG_VAL_PRINT(cL); + + // cR = * y^n -- scalar + scalar_t cR = 0; + for (size_t i = 0; i < n; ++i) + cR += a[n + i] * y_powers[i + 1] * b[i]; + cR *= y_powers[n]; + + DBG_VAL_PRINT(cR); + + // L = y^-n * a1 * g2 + b2 * h1 + cL * G + dL * H + dL2 * H2 -- point + point_t sum = c_point_0; + for (size_t i = 0; i < n; ++i) + sum += a[i] * g[n + i]; + point_t L; + CT::calc_pedersen_commitment_2(cL, dL, dL2, L); + for (size_t i = 0; i < n; ++i) + L += b[n + i] * h[i]; + L += y_inverse_powers[n] * sum; + L *= c_scalar_1div8; + DBG_VAL_PRINT(L); + + // R = y^n * a2 * g1 + b1 * h2 + cR * G + dR * H + dR2 * H2 -- point + sum.zero(); + for (size_t i = 0; i < n; ++i) + sum += a[n + i] * g[i]; + point_t R; + CT::calc_pedersen_commitment_2(cR, dR, dR2, R); + for (size_t i = 0; i < n; ++i) + R += b[i] * h[n + i]; + R += y_powers[n] * sum; + R *= c_scalar_1div8; + DBG_VAL_PRINT(R); + + // put L, R to the sig + L.to_public_key(sig.L[ni]); + R.to_public_key(sig.R[ni]); + + // update the transcript + hsc.add_scalar(e); + hsc.add_pub_key(sig.L[ni]); + hsc.add_pub_key(sig.R[ni]); + e = hsc.calc_hash(); + DBG_VAL_PRINT(e); + + // recalculate arguments for the next round + scalar_t e_squared = e * e; + scalar_t e_inverse = e.reciprocal(); + scalar_t e_inverse_squared = e_inverse * e_inverse; + scalar_t e_y_inv_n = e * y_inverse_powers[n]; + scalar_t e_inv_y_n = e_inverse * y_powers[n]; + + // g_hat = e^-1 * g1 + (e * y^-n) * g2 -- vector of points + for (size_t i = 0; i < n; ++i) + g[i] = e_inverse * g[i] + e_y_inv_n * g[n + i]; + + // h_hat = e * h1 + e^-1 * h2 -- vector of points + for (size_t i = 0; i < n; ++i) + h[i] = e * h[i] + e_inverse * h[n + i]; + + // P_hat = e^2 * L + P + e^-2 * R -- point + + // a_hat = e * a1 + e^-1 * y^n * a2 -- vector of scalars + for (size_t i = 0; i < n; ++i) + a[i] = e * a[i] + e_inv_y_n * a[n + i]; + + // b_hat = e^-1 * b1 + e * b2 -- vector of scalars + for (size_t i = 0; i < n; ++i) + b[i] = e_inverse * b[i] + e * b[n + i]; + + // alpha_hat_1 = e^2 * dL + alpha_1 + e^-2 * dR -- scalar + // alpha_hat_2 = e^2 * dL2 + alpha_2 + e^-2 * dR2 -- scalar + alpha_hat_1 += e_squared * dL + e_inverse_squared * dR; + alpha_hat_2 += e_squared * dL2 + e_inverse_squared * dR2; + + // run next iteraton zk-WIP(g_hat, h_hat, G, H, H2, P_hat, a_hat, b_hat, alpha_hat_1, alpha_hat_2) + } + DBG_PRINT(""); + + // zk-WIP last round + scalar_t r = scalar_t::random(); + scalar_t s = scalar_t::random(); + scalar_t delta_1 = scalar_t::random(), delta_2 = scalar_t::random(); + scalar_t eta_1 = scalar_t::random(), eta_2 = scalar_t::random(); + DBG_VAL_PRINT(r); + DBG_VAL_PRINT(s); + DBG_VAL_PRINT(delta_1); DBG_VAL_PRINT(delta_2); + DBG_VAL_PRINT(eta_1); DBG_VAL_PRINT(eta_2); + + // A = r * g + s * h + (r y b + s y a) * G + delta_1 * H + delta_2 * H2 -- point + point_t A = c_point_0; + CT::calc_pedersen_commitment_2(y * (r * b[0] + s * a[0]), delta_1, delta_2, A); + A += r * g[0] + s * h[0]; + A *= c_scalar_1div8; + A.to_public_key(sig.A); + DBG_VAL_PRINT(A); + + // B = (r * y * s) * G + eta_1 * H + eta_2 * H2 + point_t B = c_point_0; + CT::calc_pedersen_commitment_2(r * y * s, eta_1, eta_2, B); + B *= c_scalar_1div8; + B.to_public_key(sig.B); + DBG_VAL_PRINT(B); + + // update the transcript + hsc.add_scalar(e); + hsc.add_pub_key(sig.A); + hsc.add_pub_key(sig.B); + e = hsc.calc_hash(); + DBG_VAL_PRINT(e); + + // finalize the signature + sig.r = r + e * a[0]; + sig.s = s + e * b[0]; + sig.delta_1 = eta_1 + e * delta_1 + e * e * alpha_hat_1; + sig.delta_2 = eta_2 + e * delta_2 + e * e * alpha_hat_2; + DBG_VAL_PRINT(sig.r); + DBG_VAL_PRINT(sig.s); + DBG_VAL_PRINT(sig.delta_1); + DBG_VAL_PRINT(sig.delta_2); + + return true; +#undef CHECK_AND_FAIL_WITH_ERROR_IF_FALSE + } // bppe_gen() + + + struct bppe_sig_commit_ref_t + { + bppe_sig_commit_ref_t(const bppe_signature& sig, const std::vector& commitments) + : sig(sig) + , commitments(commitments) + {} + const bppe_signature& sig; + const std::vector& commitments; + }; + + + template + bool bppe_verify(const std::vector& sigs, uint8_t* p_err = nullptr) + { +#define CHECK_AND_FAIL_WITH_ERROR_IF_FALSE(cond, err_code) \ + if (!(cond)) { LOG_PRINT_RED("bppe_verify: \"" << #cond << "\" is false at " << LOCATION_SS << ENDL << "error code = " << err_code, LOG_LEVEL_3); \ + if (p_err) { *p_err = err_code; } return false; } + + DBG_PRINT(ENDL << " . . . . bppe_verify() . . . . "); + + const size_t kn = sigs.size(); + CHECK_AND_FAIL_WITH_ERROR_IF_FALSE(kn > 0, 1); + + struct intermediate_element_t + { + scalar_t y; + scalar_t z; + scalar_t z_sq; + scalar_vec_t e; + scalar_vec_t e_sq; + scalar_t e_final; + scalar_t e_final_sq; + size_t inv_e_offset; // offset in batch_for_inverse + size_t inv_y_offset; // offset in batch_for_inverse + size_t c_bpp_log2_m; + size_t c_bpp_m; + size_t c_bpp_mn; + point_t A; + point_t A0; + point_t B; + std::vector L; + std::vector R; + }; + std::vector interms(kn); + + size_t c_bpp_log2_m_max = 0; + for (size_t k = 0; k < kn; ++k) + { + const bppe_sig_commit_ref_t& bsc = sigs[k]; + const bppe_signature& sig = bsc.sig; + CHECK_AND_FAIL_WITH_ERROR_IF_FALSE(bsc.commitments.size() > 0, 2); + CHECK_AND_FAIL_WITH_ERROR_IF_FALSE(sig.L.size() > 0 && sig.L.size() == sig.R.size(), 3); + CHECK_AND_FAIL_WITH_ERROR_IF_FALSE(sig.r.is_reduced() && sig.s.is_reduced() && sig.delta_1.is_reduced() && sig.delta_2.is_reduced(), 4); + + intermediate_element_t& interm = interms[k]; + interm.c_bpp_log2_m = constexpr_ceil_log2(bsc.commitments.size()); + if (c_bpp_log2_m_max < interm.c_bpp_log2_m) + c_bpp_log2_m_max = interm.c_bpp_log2_m; + + CHECK_AND_FAIL_WITH_ERROR_IF_FALSE(sig.L.size() == interm.c_bpp_log2_m + CT::c_bpp_log2_n, 5); + + interm.c_bpp_m = 1ull << interm.c_bpp_log2_m; + interm.c_bpp_mn = interm.c_bpp_m * CT::c_bpp_n; + + CHECK_AND_FAIL_WITH_ERROR_IF_FALSE(interm.A0.from_public_key(sig.A0), 6); + CHECK_AND_FAIL_WITH_ERROR_IF_FALSE(interm.A.from_public_key(sig.A), 7); + CHECK_AND_FAIL_WITH_ERROR_IF_FALSE(interm.B.from_public_key(sig.B), 8); + interm.L.resize(sig.L.size()); + interm.R.resize(sig.R.size()); + for (size_t i = 0; i < interm.L.size(); ++i) + { + CHECK_AND_FAIL_WITH_ERROR_IF_FALSE(interm.L[i].from_public_key(sig.L[i]), 9); + CHECK_AND_FAIL_WITH_ERROR_IF_FALSE(interm.R[i].from_public_key(sig.R[i]), 10); + } + } + const size_t c_bpp_m_max = 1ull << c_bpp_log2_m_max; + const size_t c_bpp_mn_max = c_bpp_m_max * CT::c_bpp_n; + const size_t c_bpp_LR_size_max = c_bpp_log2_m_max + CT::c_bpp_log2_n; + + + // + // prepare stuff + // + /* + std::vector g(c_bpp_mn_max), h(c_bpp_mn_max); + for (size_t i = 0; i < c_bpp_mn_max; ++i) + { + g[i] = CT::get_generator(false, i); + h[i] = CT::get_generator(true, i); + } + */ + + scalar_vec_t batch_for_inverse; + batch_for_inverse.reserve(kn + kn * c_bpp_LR_size_max); + + + for (size_t k = 0; k < kn; ++k) + { + DBG_PRINT(ENDL << "SIG #" << k); + const bppe_sig_commit_ref_t& bsc = sigs[k]; + const bppe_signature& sig = bsc.sig; + intermediate_element_t& interm = interms[k]; + + // restore y and z + // using e as Fiat-Shamir transcript + scalar_t e = CT::get_initial_transcript(); + DBG_PRINT("initial transcript: " << e); + hash_helper_t::hs_t hsc; + CT::update_transcript(hsc, e, bsc.commitments); + // calculate scalar challenges y and z + hsc.add_scalar(e); + hsc.add_pub_key(sig.A0); + hsc.assign_calc_hash(interm.y); + interm.z = hash_helper_t::hs(interm.y); + interm.z_sq = interm.z * interm.z; + DBG_VAL_PRINT(interm.y); + DBG_VAL_PRINT(interm.z); + e = interm.z; // transcript for further steps + + interm.inv_y_offset = batch_for_inverse.size(); + batch_for_inverse.push_back(interm.y); + interm.inv_e_offset = batch_for_inverse.size(); + + interm.e.resize(sig.L.size()); + interm.e_sq.resize(sig.L.size()); + + for (size_t i = 0; i < sig.L.size(); ++i) + { + hsc.add_scalar(e); + hsc.add_pub_key(sig.L[i]); + hsc.add_pub_key(sig.R[i]); + hsc.assign_calc_hash(e); + interm.e[i] = e; + interm.e_sq[i] = e * e; + DBG_PRINT("e[" << i << "]: " << e); + batch_for_inverse.push_back(e); + } + + hsc.add_scalar(e); + hsc.add_pub_key(sig.A); + hsc.add_pub_key(sig.B); + hsc.assign_calc_hash(interm.e_final); + interm.e_final_sq = interm.e_final * interm.e_final; + DBG_VAL_PRINT(interm.e_final); + } + + batch_for_inverse.invert(); + + // Notation: + // 1_vec ^ n = (1, 1, 1, ..., 1) + // 2_vec ^ n = (2^0, 2^1, 2^2, ..., 2^(n-1)) + // -1_vec ^ n = ((-1)^0, (-1)^1, (-1)^2, ... (-1)^(n-1)) = (1, -1, 1, -1, ...) + // y<^n = (y^n, y^(n-1), ..., y^1) + // y>^n = (y^1, y^2, ..., y^n) + + // from Zarcanum page 24, Fig D.1: + // Verifier outputs Accept IFF the following holds: + // P^e^2 * A^e * B == g ^ (r' e) * h ^ (s' e) * G ^ (r' y s') * H ^ delta'_1 * H2 ^ delta'_2 + // (where g and h are calculated in each round) + // The same equation in additive notation: + // e^2 * P + e * A + B == (r' * e) * g + (s' * e) * h + (r' y s') * G + delta'_1 * H + delta'_2 * H2 + // <=> + // (r' * e) * g + (s' * e) * h + (r' y s') * G + delta'_1 * H + delta'_2 * H2 - e^2 * P - e * A - B == 0 (*) + // where A, B, r', s', delta'_1, delta'_2 is taken from the signature + // and P_{k+1} = e^2 * L_k + P_k + e^-2 * R_k for all rounds + // + // from Zarcanum preprint page 33, Fig D.3: + // P and V computes: + // A_hat = A0 + (- 1^(mn) * z) * g + (d o y<^(mn) + 1^(mn) * z) * h + + // + y^(mn+1) * (SUM{j=1..m} z^(2j) * V_j) + + // + (z*SUM(y^>mn) - z*y^(mn+1)*SUM(d) - z^2 * SUM(y^>mn)) * G + // (calculated once) + // + // As suggested in BPP preprint Section 6.1 "Practical Optimizations": + // 1) g and h exponentianions can be optimized in order not to be calculated at each round + // as the following (page 20, with delta'_2 and H2 added): + // + // (r' * e * s_vec) * g + (s' * e * s'_vec) * h + (r' y s') * G + delta'_1 * H + delta'_2 * H2 - + // - e^2 * A_hat + // - SUM{j=1..log(n)}(e_final^2 * e_j^2 * L_j + e_final^2 * e_j^-2 * R_j) + // - e * A - B = 0 (**) + // + // where: + // g, h - vector of fixed generators + // s_vec_i = y^(1-i) * PROD{j=1..log(n)}(e_j ^ b(i,j)) + // s'_vec_i = PROD{j=1..log(n)}(e_j ^ -b(i,j)) + // b(i, j) = { 2 * ((1<<(j-1)) & (i-1)) - 1) (counting both from 1) (page 20) + // b(i, j) = { 2 * ((1< + + // (r' * e * s_vec) * g + (s' * e * s'_vec) * h + (r' y s') * G + delta'_1 * H + delta'_2 * H2 - + // - e^2 * (A0 + (- 1^(mn) * z) * g + (d o y<^(mn) + 1^(mn) * z) * h + + // + y^(mn+1) * (SUM{j=1..m} z^(2j) * V_j) + + // + (z*SUM(y^>mn) - z*y^(mn+1)*SUM(d) - z^2 * SUM(y^>mn)) * G + // ) + // - SUM{j=1..log(n)}(e_final^2 * e_j^2 * L_j + e_final^2 * e_j^-2 * R_j) + // - e * A - B = 0 + + // => + + // (for single signature) + // + // (r' * e * s_vec - e^2 * (- 1_vec^(mn) * z)) * g | these are + // + (s' * e * s'_vec - e^2 * (d o y<^(mn) + 1_vec^(mn) * z)) * h | fixed generators + // + (r' y s' - e^2 * ((z - z^2)*SUM(y^>mn) - z*y^(mn+1)*SUM(d)) * G | across all + // + delta'_1 * H | the signatures + // + delta'_2 * H2 | the signatures + // + // - e^2 * A0 + // - e^2 * y^(mn+1) * (SUM{j=1..m} z^(2j) * V_j)) + // - e^2 * SUM{j=1..log(n)}(e_j^2 * L_j + e_j^-2 * R_j) + // - e * A - B = 0 (***) + // + // All (***) will be muptiplied by random weightning factor and then summed up. + + // Calculate cummulative sclalar multiplicand for fixed generators across all the sigs. + scalar_vec_t g_scalars; + g_scalars.resize(c_bpp_mn_max, 0); + scalar_vec_t h_scalars; + h_scalars.resize(c_bpp_mn_max, 0); + scalar_t G_scalar = 0; + scalar_t H_scalar = 0; + scalar_t H2_scalar = 0; + point_t summand = c_point_0; + + for (size_t k = 0; k < kn; ++k) + { + DBG_PRINT(ENDL << "SIG #" << k); + const bppe_sig_commit_ref_t& bsc = sigs[k]; + const bppe_signature& sig = bsc.sig; + intermediate_element_t& interm = interms[k]; + + // random weightning factor for speed-optimized batch verification (preprint page 20) + const scalar_t rwf = scalar_t::random(); + DBG_PRINT("rwf: " << rwf); + + // prepare d vector (see also d structure description in proof function) + scalar_mat_t d(interm.c_bpp_mn); + d(0, 0) = interm.z_sq; + // first row + for (size_t i = 1; i < interm.c_bpp_m; ++i) + d(i, 0) = d(i - 1, 0) * interm.z_sq; + // all rows + for (size_t j = 1; j < CT::c_bpp_n; ++j) + for (size_t i = 0; i < interm.c_bpp_m; ++i) + d(i, j) = d(i, j - 1) + d(i, j - 1); + // sum(d) (see also note in proof function for this) + // TODO: check for not 2^64 version + static const scalar_t c_scalar_2_power_n_minus_1 = { 0xffffffffffffffff, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000 }; + const scalar_t sum_d = c_scalar_2_power_n_minus_1 * sum_of_powers(interm.z_sq, interm.c_bpp_log2_m); + + DBG_PRINT("Hs(d): " << d.calc_hs()); + DBG_PRINT("sum(d): " << sum_d); + + const scalar_t& y_inv = batch_for_inverse[interm.inv_y_offset]; + auto get_e_inv = [&](size_t i) { return batch_for_inverse[interm.inv_e_offset + i]; }; // i belongs to [0; L.size()-1] + + // prepare s_vec (unlike the paper here we moved y-component out of s_vec for convenience, so s_vec'[x] = s_vec[~x & (MN-1)]) + // complexity (sc_mul's): MN+2*log2(MN)-2 + // the idea is the following: + // s_vec[00000b] = ... * (e_4)^-1 * (e_3)^-1 * (e_2)^-1 * (e_1)^-1 * (e_0)^-1 + // s_vec[00101b] = ... * (e_4)^-1 * (e_3)^-1 * (e_2)^+1 * (e_1)^-1 * (e_0)^+1 + const size_t log2_mn = sig.L.size(); // at the beginning we made sure that sig.L.size() == c_bpp_log2_m + c_bpp_log2_n + scalar_vec_t s_vec(interm.c_bpp_mn); + s_vec[0] = get_e_inv(0); + for (size_t i = 1; i < log2_mn; ++i) + s_vec[0] *= get_e_inv(i); // s_vec[0] = (e_0)^-1 * (e_1)^-1 * .. (e_{log2_mn-1})^-1 + DBG_PRINT("[0] " << s_vec[0]); + for (size_t i = 1; i < interm.c_bpp_mn; ++i) + { + size_t base_el_index = i & (i - 1); // base element index: 0, 0, 2, 0, 4, 4, 6, 0, 8, 8, 10... base element differs in one bit (0) from the current one (1) + size_t bit_index = log2_mn - calc_lsb_32((uint32_t)i) - 1; // the bit index where current element has the difference with the base + s_vec[i] = s_vec[base_el_index] * interm.e_sq[bit_index]; // (e_j)^-1 * (e_j)^2 = (e_j)^+1 + DBG_PRINT("[" << i << "] " << " " << base_el_index << ", " << bit_index << " : " << s_vec[i]); + } + + // prepare y_inv vector + scalar_vec_t y_inverse_powers(interm.c_bpp_mn); + y_inverse_powers[0] = 1; + for (size_t i = 1; i < interm.c_bpp_mn; ++i) + y_inverse_powers[i] = y_inverse_powers[i - 1] * y_inv; + + // y^(mn+1) + scalar_t y_power_mnp1 = interm.y; + for (size_t i = 0; i < log2_mn; ++i) + y_power_mnp1 *= y_power_mnp1; + y_power_mnp1 *= interm.y; + DBG_VAL_PRINT(y_power_mnp1); + + // now calculate all multiplicands for common generators + + // g vector multiplicands: + // rwf * (r' * e * (1, y^-1, y^-2, ...) o s_vec + e^2 * z) = + // rwf * r' * e * ((1, y^-1, ...) o s_vec) + rwf * e^2 * z * (1, 1, ...) + scalar_t rwf_e_sq_z = rwf * interm.e_final_sq * interm.z; + scalar_t rwf_r_e = rwf * interm.e_final * sig.r; + for (size_t i = 0; i < interm.c_bpp_mn; ++i) + g_scalars[i] += rwf_r_e * y_inverse_powers[i] * s_vec[i] + rwf_e_sq_z; + + DBG_PRINT("Hs(g_scalars): " << g_scalars.calc_hs()); + + // h vector multiplicands: + // rwf * (s' * e * s'_vec - e^2 * (d o y<^(mn) + 1_vec^(mn) * z)) + // rwf * s' * e * s'_vec - rwf * e^2 * z * (1, 1...) - rwf * e^2 * (d o y<^(mn)) + //scalar_t rwf_e_sq_z = rwf * interm.e_final_sq * interm.z; + scalar_t rwf_s_e = rwf * sig.s * interm.e_final; + scalar_t rwf_e_sq_y = rwf * interm.e_final_sq * interm.y; + for (size_t i = interm.c_bpp_mn - 1; i != SIZE_MAX; --i) + { + h_scalars[i] += rwf_s_e * s_vec[interm.c_bpp_mn - 1 - i] - rwf_e_sq_z - rwf_e_sq_y * d[i]; + rwf_e_sq_y *= interm.y; + } + + DBG_PRINT("Hs(h_scalars): " << h_scalars.calc_hs()); + + // G point multiplicands: + // rwf * (r' y s' - e ^ 2 * ((z - z ^ 2)*SUM(y^>mn) - z * y^(mn+1) * SUM(d)) = + // = rwf * r' y s' - rwf * e^2 * (z - z ^ 2)*SUM(y^>mn) + rwf * e^2 * z * y^(mn+1) * SUM(d) + G_scalar += rwf * sig.r * interm.y * sig.s + rwf_e_sq_y * sum_d * interm.z; + G_scalar -= rwf * interm.e_final_sq * (interm.z - interm.z_sq) * sum_of_powers(interm.y, log2_mn); + DBG_PRINT("sum_y: " << sum_of_powers(interm.y, log2_mn)); + DBG_PRINT("G_scalar: " << G_scalar); + + // H point multiplicands: + // rwf * delta_1 + H_scalar += rwf * sig.delta_1; + DBG_PRINT("H_scalar: " << H_scalar); + + // H2 point multiplicands: + // rwf * delta_2 + H2_scalar += rwf * sig.delta_2; + DBG_PRINT("H2_scalar: " << H2_scalar); + + // uncommon generators' multiplicands + point_t summand_8 = c_point_0; // this summand to be multiplied by 8 before adding to the main summand + // - rwf * e^2 * A0 + summand_8 -= rwf * interm.e_final_sq * interm.A0; + DBG_PRINT("A0_scalar: " << c_scalar_Lm1 * interm.e_final_sq * rwf); + + // - rwf * e^2 * y^(mn+1) * (SUM{j=1..m} (z^2)^j * V_j)) + scalar_t e_sq_y_mn1_z_sq_power = rwf * interm.e_final_sq * y_power_mnp1; + for (size_t j = 0; j < bsc.commitments.size(); ++j) + { + e_sq_y_mn1_z_sq_power *= interm.z_sq; + summand_8 -= e_sq_y_mn1_z_sq_power * bsc.commitments[j]; + DBG_PRINT("V_scalar[" << j << "]: " << c_scalar_Lm1 * e_sq_y_mn1_z_sq_power); + } + + // - rwf * e^2 * SUM{j=1..log(n)}(e_j^2 * L_j + e_j^-2 * R_j) + scalar_t rwf_e_sq = rwf * interm.e_final_sq; + for (size_t j = 0; j < log2_mn; ++j) + { + summand_8 -= rwf_e_sq * (interm.e_sq[j] * interm.L[j] + get_e_inv(j) * get_e_inv(j) * interm.R[j]); + DBG_PRINT("L_scalar[" << j << "]: " << c_scalar_Lm1 * rwf_e_sq * interm.e_sq[j]); + DBG_PRINT("R_scalar[" << j << "]: " << c_scalar_Lm1 * rwf_e_sq * get_e_inv(j) * get_e_inv(j)); + } + + // - rwf * e * A - rwf * B = 0 + summand_8 -= rwf * interm.e_final * interm.A + rwf * interm.B; + DBG_PRINT("A_scalar: " << c_scalar_Lm1 * rwf * interm.e_final); + DBG_PRINT("B_scalar: " << c_scalar_Lm1 * rwf); + + summand_8.modify_mul8(); + summand += summand_8; + } + + point_t GH_exponents = c_point_0; + CT::calc_pedersen_commitment_2(G_scalar, H_scalar, H2_scalar, GH_exponents); + bool result = multiexp_and_check_being_zero(g_scalars, h_scalars, summand + GH_exponents); + if (result) + DBG_PRINT(ENDL << " . . . . bppe_verify() -- SUCCEEDED!!!" << ENDL); + return result; +#undef CHECK_AND_FAIL_WITH_ERROR_IF_FALSE + } + +} // namespace crypto diff --git a/src/crypto/range_proofs.h b/src/crypto/range_proofs.h index 623c5af0..2f7fcf00 100644 --- a/src/crypto/range_proofs.h +++ b/src/crypto/range_proofs.h @@ -148,3 +148,4 @@ namespace crypto } // namespace crypto #include "range_proof_bpp.h" +#include "range_proof_bppe.h" diff --git a/tests/functional_tests/crypto_tests_range_proofs.h b/tests/functional_tests/crypto_tests_range_proofs.h index 94f4db0b..3ccdc7f4 100644 --- a/tests/functional_tests/crypto_tests_range_proofs.h +++ b/tests/functional_tests/crypto_tests_range_proofs.h @@ -180,3 +180,82 @@ TEST(bpp, power_256) return true; } + + +// +// tests for Bulletproofs+ Extended (with double-blinded commitments) +// + + +TEST(bppe, basics) +{ + /* + srand(0); + for (size_t i = 0; i < 10; ++i) + std::cout << scalar_t::random().to_string_as_secret_key() << ENDL; + */ + + scalar_vec_t values = { 5 }; + scalar_vec_t masks = { 0 }; + scalar_vec_t masks_2 = { 0 }; + + bppe_signature bppe_sig; + std::vector commitments; + uint8_t err = 0; + + bool r = bppe_gen>(values, masks, masks_2, bppe_sig, commitments, &err); + + ASSERT_TRUE(r); + + return true; +} + +TEST(bppe, two) +{ + std::vector signatures_vector; + signatures_vector.reserve(10); + std::vector> commitments_vector; + commitments_vector.reserve(10); + + std::vector sigs; + uint8_t err = 0; + bool r = false; + + { + signatures_vector.resize(signatures_vector.size() + 1); + bppe_signature &bppe_sig = signatures_vector.back(); + commitments_vector.resize(commitments_vector.size() + 1); + std::vector& commitments = commitments_vector.back(); + + scalar_vec_t values = { 5 }; + scalar_vec_t masks = { scalar_t(77 + 256 * 77) }; + scalar_vec_t masks2 = { scalar_t(88 + 256 * 88) }; + + r = bppe_gen>(values, masks, masks2, bppe_sig, commitments, &err); + ASSERT_TRUE(r); + + sigs.emplace_back(bppe_sig, commitments); + } + + { + signatures_vector.resize(signatures_vector.size() + 1); + bppe_signature &bppe_sig = signatures_vector.back(); + commitments_vector.resize(commitments_vector.size() + 1); + std::vector& commitments = commitments_vector.back(); + + scalar_vec_t values = { 5, 700, 8 }; + scalar_vec_t masks = { scalar_t(77 + 256 * 77), scalar_t(255), scalar_t(17) }; + scalar_vec_t masks2 = { scalar_t(88 + 256 * 88), scalar_t(1), scalar_t(19) }; + + r = bppe_gen>(values, masks, masks2, bppe_sig, commitments, &err); + ASSERT_TRUE(r); + + sigs.emplace_back(bppe_sig, commitments); + } + + r = bppe_verify>(sigs, &err); + ASSERT_TRUE(r); + + + return true; +} From 024e07c2d924abb5ef4ada07619a6d8f94416ca6 Mon Sep 17 00:00:00 2001 From: cryptozoidberg Date: Tue, 12 Apr 2022 21:04:55 +0200 Subject: [PATCH 10/15] [COVERITY] Fixed coveerity issue 391947 Unchecked return value from library --- src/common/ntp.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/common/ntp.cpp b/src/common/ntp.cpp index b7f8a076..db55610a 100644 --- a/src/common/ntp.cpp +++ b/src/common/ntp.cpp @@ -194,7 +194,12 @@ namespace tools ntp_packet packet_sent = AUTO_VAL_INIT(packet_sent); packet_sent.li_vn_mode = 0x1b; auto packet_sent_time = std::chrono::high_resolution_clock::now(); - socket.send_to(boost::asio::buffer(&packet_sent, sizeof packet_sent), receiver_endpoint); + auto send_res = socket.send_to(boost::asio::buffer(&packet_sent, sizeof packet_sent), receiver_endpoint); + if (send_res != sizeof packet_sent) + { + LOG_PRINT_L3("NTP: get_ntp_time(" << host_name << "): wrong send_res: " << send_res << ", expected sizeof packet_sent = " << sizeof packet_sent); + return 0; + } ntp_packet packet_received = AUTO_VAL_INIT(packet_received); boost::asio::ip::udp::endpoint sender_endpoint; From a0211f2b27e1955d8fae63a72ccc79feeef5ffc1 Mon Sep 17 00:00:00 2001 From: sowle Date: Fri, 15 Apr 2022 21:27:16 +0200 Subject: [PATCH 11/15] crypto tests: ASSERT_NEQ --- tests/functional_tests/crypto_tests.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/functional_tests/crypto_tests.cpp b/tests/functional_tests/crypto_tests.cpp index 68350097..c15d3869 100644 --- a/tests/functional_tests/crypto_tests.cpp +++ b/tests/functional_tests/crypto_tests.cpp @@ -473,6 +473,7 @@ uint64_t hash_64(const void* data, size_t size) #define ASSERT_TRUE(expr) CHECK_AND_ASSERT_MES(expr, false, "This is not true: " #expr) #define ASSERT_FALSE(expr) CHECK_AND_ASSERT_MES((expr) == false, false, "This is not false: " #expr) #define ASSERT_EQ(a, b) CHECK_AND_ASSERT_MES(a == b, false, #a " != " #b "\n " << a << " != " << b) +#define ASSERT_NEQ(a, b) CHECK_AND_ASSERT_MES(a != b, false, #a " == " #b "\n " << a) typedef bool(*bool_func_ptr_t)(); static std::vector> g_tests; From b0e8e6c2eb2611060add7b3c566c267f25de2286 Mon Sep 17 00:00:00 2001 From: sowle Date: Fri, 15 Apr 2022 21:29:08 +0200 Subject: [PATCH 12/15] crypto: scalar_t: get_bit, set_bit, clear_bit, power_of_2 implemented; crypto_sc_set_bit_clear_bit test added --- src/crypto/crypto-sugar.h | 24 ++++++++++++-- tests/functional_tests/crypto_tests.cpp | 43 ++++++++++++++++++------- 2 files changed, 53 insertions(+), 14 deletions(-) diff --git a/src/crypto/crypto-sugar.h b/src/crypto/crypto-sugar.h index d1928a92..a2681642 100644 --- a/src/crypto/crypto-sugar.h +++ b/src/crypto/crypto-sugar.h @@ -431,13 +431,31 @@ namespace crypto return result; } - bool get_bit(size_t bit_index) const + // Little-endian assumed; TODO: consider Big-endian support + bool get_bit(uint8_t bit_index) const { - if (bit_index > 255) - return false; // TODO: consider performace implications return (m_u64[bit_index >> 6] & (1ull << (bit_index & 63))) != 0; } + // Little-endian assumed; TODO: consider Big-endian support + void set_bit(size_t bit_index) + { + m_u64[bit_index >> 6] |= (1ull << (bit_index & 63)); + } + + // Little-endian assumed; TODO: consider Big-endian support + void clear_bit(size_t bit_index) + { + m_u64[bit_index >> 6] &= ~(1ull << (bit_index & 63)); + } + + static scalar_t power_of_2(uint8_t exponent) + { + scalar_t result = 0; + result.set_bit(exponent); + return result; + } + }; // struct scalar_t // diff --git a/tests/functional_tests/crypto_tests.cpp b/tests/functional_tests/crypto_tests.cpp index c15d3869..e4e0c63e 100644 --- a/tests/functional_tests/crypto_tests.cpp +++ b/tests/functional_tests/crypto_tests.cpp @@ -1812,40 +1812,61 @@ TEST(crypto, sc_get_bit) scalar_t v = 0; // all bits are 0 for (size_t n = 0; n < 256; ++n) { - ASSERT_EQ(v.get_bit(n), false); + ASSERT_EQ(v.get_bit(static_cast(n)), false); } v = c_scalar_256m1; // all bits are 1 for (size_t n = 0; n < 256; ++n) { - ASSERT_EQ(v.get_bit(n), true); + ASSERT_EQ(v.get_bit(static_cast(n)), true); } // bits out of the [0; 255] range supposed to be always 0 for (size_t n = 256; n < 2048; ++n) { - ASSERT_EQ(v.get_bit(n), false); + ASSERT_EQ(v.get_bit(static_cast(n)), false); } // check random value const scalar_t x = scalar_t::random(); for (size_t n = 0; n < 64; ++n) - ASSERT_EQ(x.get_bit(n), ((x.m_u64[0] & (1ull << (n - 0))) != 0)); + ASSERT_EQ(x.get_bit(static_cast(n)), ((x.m_u64[0] & (1ull << (n - 0))) != 0)); for (size_t n = 64; n < 128; ++n) - ASSERT_EQ(x.get_bit(n), ((x.m_u64[1] & (1ull << (n - 64))) != 0)); + ASSERT_EQ(x.get_bit(static_cast(n)), ((x.m_u64[1] & (1ull << (n - 64))) != 0)); for (size_t n = 128; n < 192; ++n) - ASSERT_EQ(x.get_bit(n), ((x.m_u64[2] & (1ull << (n - 128))) != 0)); + ASSERT_EQ(x.get_bit(static_cast(n)), ((x.m_u64[2] & (1ull << (n - 128))) != 0)); for (size_t n = 192; n < 256; ++n) - ASSERT_EQ(x.get_bit(n), ((x.m_u64[3] & (1ull << (n - 192))) != 0)); - - // bits out of the [0; 255] range supposed to be always 0 - for (size_t n = 256; n < 2048; ++n) - ASSERT_EQ(x.get_bit(n), false); + ASSERT_EQ(x.get_bit(static_cast(n)), ((x.m_u64[3] & (1ull << (n - 192))) != 0)); return true; } +TEST(crypto, sc_set_bit_clear_bit) +{ + static_assert(sizeof(scalar_t) * 8 == 256, "size missmatch"); + + // check random value + const scalar_t x = scalar_t::random(); + scalar_t y = scalar_t::random(); + ASSERT_NEQ(x, y); + + uint8_t i = 0; + do + { + if (x.get_bit(i)) + y.set_bit(i); + else + y.clear_bit(i); + } while(++i != 0); + + ASSERT_EQ(x, y); + + return true; +} + + + // // test's runner // From 0fd6406158bd565c9bc181913fae5be2eb74e0bd Mon Sep 17 00:00:00 2001 From: sowle Date: Mon, 18 Apr 2022 18:12:15 +0200 Subject: [PATCH 13/15] crypto: BPP & BPPE: get_2_to_the_power_of_N_minus_1() --- src/crypto/range_proof_bpp.h | 3 +-- src/crypto/range_proof_bppe.h | 4 +--- src/crypto/range_proofs.h | 6 ++++++ 3 files changed, 8 insertions(+), 5 deletions(-) diff --git a/src/crypto/range_proof_bpp.h b/src/crypto/range_proof_bpp.h index a8b68807..88bd7092 100644 --- a/src/crypto/range_proof_bpp.h +++ b/src/crypto/range_proof_bpp.h @@ -573,8 +573,7 @@ namespace crypto for (size_t i = 0; i < interm.c_bpp_m; ++i) d(i, j) = d(i, j - 1) + d(i, j - 1); // sum(d) (see also note in proof function for this) - static const scalar_t c_scalar_2_power_n_minus_1 = { 0xffffffffffffffff, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000 }; - const scalar_t sum_d = c_scalar_2_power_n_minus_1 * sum_of_powers(interm.z_sq, interm.c_bpp_log2_m); + const scalar_t sum_d = CT::get_2_to_the_power_of_N_minus_1() * sum_of_powers(interm.z_sq, interm.c_bpp_log2_m); DBG_PRINT("Hs(d): " << d.calc_hs()); DBG_PRINT("sum(d): " << sum_d); diff --git a/src/crypto/range_proof_bppe.h b/src/crypto/range_proof_bppe.h index 83fc83c2..8785dad5 100644 --- a/src/crypto/range_proof_bppe.h +++ b/src/crypto/range_proof_bppe.h @@ -588,9 +588,7 @@ namespace crypto for (size_t i = 0; i < interm.c_bpp_m; ++i) d(i, j) = d(i, j - 1) + d(i, j - 1); // sum(d) (see also note in proof function for this) - // TODO: check for not 2^64 version - static const scalar_t c_scalar_2_power_n_minus_1 = { 0xffffffffffffffff, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000 }; - const scalar_t sum_d = c_scalar_2_power_n_minus_1 * sum_of_powers(interm.z_sq, interm.c_bpp_log2_m); + const scalar_t sum_d = CT::get_2_to_the_power_of_N_minus_1() * sum_of_powers(interm.z_sq, interm.c_bpp_log2_m); DBG_PRINT("Hs(d): " << d.calc_hs()); DBG_PRINT("sum(d): " << sum_d); diff --git a/src/crypto/range_proofs.h b/src/crypto/range_proofs.h index 2f7fcf00..bcd03393 100644 --- a/src/crypto/range_proofs.h +++ b/src/crypto/range_proofs.h @@ -110,6 +110,12 @@ namespace crypto return generators[2 * index + (select_H ? 1 : 0)]; } + static const scalar_t& get_2_to_the_power_of_N_minus_1() + { + static scalar_t result = scalar_t::power_of_2(c_bpp_n) - 1; + return result; + } + static const point_t& bpp_H; static const point_t& bpp_H2; }; // struct bpp_crypto_trait_zano From 78372d1bde2144b1cd2d5342921ef991e07070e3 Mon Sep 17 00:00:00 2001 From: sowle Date: Tue, 19 Apr 2022 23:41:59 +0200 Subject: [PATCH 14/15] crypto: BPP and BPPE: minor improvements --- src/crypto/range_proof_bpp.h | 8 +++++--- src/crypto/range_proof_bppe.h | 8 +++++--- 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/src/crypto/range_proof_bpp.h b/src/crypto/range_proof_bpp.h index 88bd7092..cd61ca85 100644 --- a/src/crypto/range_proof_bpp.h +++ b/src/crypto/range_proof_bpp.h @@ -33,6 +33,7 @@ namespace crypto if (!(cond)) { LOG_PRINT_RED("bpp_gen: \"" << #cond << "\" is false at " << LOCATION_SS << ENDL << "error code = " << err_code, LOG_LEVEL_3); \ if (p_err) { *p_err = err_code; } return false; } + static_assert(CT::c_bpp_n <= 255, "too big N"); CHECK_AND_FAIL_WITH_ERROR_IF_FALSE(values.size() > 0 && values.size() <= CT::c_bpp_values_max && values.size() == masks.size(), 1); CHECK_AND_FAIL_WITH_ERROR_IF_FALSE(masks.is_reduced(), 3); @@ -65,7 +66,7 @@ namespace crypto for (size_t i = 0; i < values.size(); ++i) { const scalar_t& v = values[i]; - for (size_t j = 0; j < CT::c_bpp_n; ++j) + for (uint8_t j = 0; j < CT::c_bpp_n; ++j) { if (v.get_bit(j)) aLs(i, j) = c_scalar_1; // aL = 1, aR = 0 @@ -112,7 +113,7 @@ namespace crypto DBG_VAL_PRINT(z); // Computing vector d for aggregated version of the protocol (BP+ paper, page 17) - // (note: elements is stored column-by-column in memory) + // (note: elements are stored column-by-column in memory) // d = | 1 * z^(2*1), 1 * z^(2*2), 1 * z^(2*3), ..., 1 * z^(2*m) | // | 2 * z^(2*1), 2 * z^(2*2), 2 * z^(2*3), ..., 2 * z^(2*m) | // | 4 * z^(2*1), 4 * z^(2*2), 4 * z^(2*3), ..., 4 * z^(2*m) | @@ -164,7 +165,7 @@ namespace crypto DBG_VAL_PRINT(alpha_hat); - // calculate y^-1, y^-2, ... + // calculate 1, y^-1, y^-2, ... const scalar_t y_inverse = y.reciprocal(); scalar_vec_t y_inverse_powers(c_bpp_mn / 2 + 1); // the greatest power we need is c_bpp_mn/2 (at the first reduction round) y_inverse_powers[0] = 1; @@ -347,6 +348,7 @@ namespace crypto DBG_PRINT(ENDL << " . . . . bpp_verify() . . . . "); + static_assert(CT::c_bpp_n <= 255, "too big N"); const size_t kn = sigs.size(); CHECK_AND_FAIL_WITH_ERROR_IF_FALSE(kn > 0, 1); diff --git a/src/crypto/range_proof_bppe.h b/src/crypto/range_proof_bppe.h index 8785dad5..7aaed80c 100644 --- a/src/crypto/range_proof_bppe.h +++ b/src/crypto/range_proof_bppe.h @@ -34,6 +34,7 @@ namespace crypto if (!(cond)) { LOG_PRINT_RED("bppe_gen: \"" << #cond << "\" is false at " << LOCATION_SS << ENDL << "error code = " << err_code, LOG_LEVEL_3); \ if (p_err) { *p_err = err_code; } return false; } + static_assert(CT::c_bpp_n <= 255, "too big N"); CHECK_AND_FAIL_WITH_ERROR_IF_FALSE(values.size() > 0 && values.size() <= CT::c_bpp_values_max && values.size() == masks.size() && masks.size() == masks2.size(), 1); CHECK_AND_FAIL_WITH_ERROR_IF_FALSE(masks.is_reduced() && masks2.is_reduced(), 3); @@ -66,7 +67,7 @@ namespace crypto for (size_t i = 0; i < values.size(); ++i) { const scalar_t& v = values[i]; - for (size_t j = 0; j < CT::c_bpp_n; ++j) + for (uint8_t j = 0; j < CT::c_bpp_n; ++j) { if (v.get_bit(j)) aLs(i, j) = c_scalar_1; // aL = 1, aR = 0 @@ -114,7 +115,7 @@ namespace crypto DBG_VAL_PRINT(z); // Computing vector d for aggregated version of the protocol (BP+ paper, page 17) - // (note: elements is stored column-by-column in memory) + // (note: elements are stored column-by-column in memory) // d = | 1 * z^(2*1), 1 * z^(2*2), 1 * z^(2*3), ..., 1 * z^(2*m) | // | 2 * z^(2*1), 2 * z^(2*2), 2 * z^(2*3), ..., 2 * z^(2*m) | // | 4 * z^(2*1), 4 * z^(2*2), 4 * z^(2*3), ..., 4 * z^(2*m) | @@ -172,7 +173,7 @@ namespace crypto DBG_VAL_PRINT(alpha_hat_1); DBG_VAL_PRINT(alpha_hat_2); - // calculate y^-1, y^-2, ... + // calculate 1, y^-1, y^-2, ... const scalar_t y_inverse = y.reciprocal(); scalar_vec_t y_inverse_powers(c_bpp_mn / 2 + 1); // the greatest power we need is c_bpp_mn/2 (at the first reduction round) y_inverse_powers[0] = 1; @@ -359,6 +360,7 @@ namespace crypto DBG_PRINT(ENDL << " . . . . bppe_verify() . . . . "); + static_assert(CT::c_bpp_n <= 255, "too big N"); const size_t kn = sigs.size(); CHECK_AND_FAIL_WITH_ERROR_IF_FALSE(kn > 0, 1); From decbbe973c19b62db930a0412d7ca7e33614bbf7 Mon Sep 17 00:00:00 2001 From: sowle Date: Wed, 20 Apr 2022 15:36:31 +0200 Subject: [PATCH 15/15] tests: random_helper minor improvements --- tests/core_tests/random_helper.cpp | 46 ---------------------------- tests/core_tests/random_helper.h | 49 +++++++++++++++++++++++++++--- 2 files changed, 44 insertions(+), 51 deletions(-) diff --git a/tests/core_tests/random_helper.cpp b/tests/core_tests/random_helper.cpp index eac32896..724d9108 100644 --- a/tests/core_tests/random_helper.cpp +++ b/tests/core_tests/random_helper.cpp @@ -6,52 +6,6 @@ #include "chaingen.h" #include "random_helper.h" -random_state_test_restorer::random_state_test_restorer() -{ - crypto::random_prng_get_state(&m_state, sizeof m_state); -} - -random_state_test_restorer::~random_state_test_restorer() -{ - crypto::random_prng_set_state(&m_state, sizeof m_state); -} - -void random_state_test_restorer::reset_random(uint64_t seed /* = 0 */) -{ - crypto::random_prng_initialize_with_seed(seed); -} - -std::string get_random_text(size_t len) -{ - static const char text_chars[] = "abcdefghijklmnopqrstuvwxyz" "ABCDEFGHIJKLMNOPQRSTUVWXYZ" "0123456789" "~!@#$%^&*()-=_+\\/?,.<>|{}[]`';:\" "; - static const uint8_t text_chars_size = sizeof text_chars - 1; // to avoid '\0' - std::string result; - - if (len < 1) - return result; - - result.resize(len); - char* result_buf = &result[0]; - uint8_t* rnd_indices = new uint8_t[len]; - crypto::generate_random_bytes(len, rnd_indices); - - size_t n = len / 4, i; - for (i = 0; i < n; ++i) - { - result_buf[4 * i + 0] = text_chars[rnd_indices[4 * i + 0] % text_chars_size]; - result_buf[4 * i + 1] = text_chars[rnd_indices[4 * i + 1] % text_chars_size]; - result_buf[4 * i + 2] = text_chars[rnd_indices[4 * i + 2] % text_chars_size]; - result_buf[4 * i + 3] = text_chars[rnd_indices[4 * i + 3] % text_chars_size]; - } - for (size_t j = i * 4; j < len; ++j) - { - result_buf[j] = text_chars[rnd_indices[j] % text_chars_size]; - } - - delete[] rnd_indices; - return result; -} - //------------------------------------------------------------------------------ bool random_state_manupulation_test() diff --git a/tests/core_tests/random_helper.h b/tests/core_tests/random_helper.h index c9826665..360b326d 100644 --- a/tests/core_tests/random_helper.h +++ b/tests/core_tests/random_helper.h @@ -13,17 +13,56 @@ // Remebers random state at ctor, restores it at dtor struct random_state_test_restorer { - random_state_test_restorer(); - ~random_state_test_restorer(); - static void reset_random(uint64_t seed = 0); - + random_state_test_restorer() + { + crypto::random_prng_get_state(&m_state, sizeof m_state); + } + ~random_state_test_restorer() + { + crypto::random_prng_set_state(&m_state, sizeof m_state); + } + static void reset_random(uint64_t seed = 0) + { + crypto::random_prng_initialize_with_seed(seed); + } private: uint8_t m_state[RANDOM_STATE_SIZE]; }; #endif // #ifdef USE_INSECURE_RANDOM_RPNG_ROUTINES -std::string get_random_text(size_t len); +inline std::string get_random_text(size_t len) +{ + { + static const char text_chars[] = "abcdefghijklmnopqrstuvwxyz" "ABCDEFGHIJKLMNOPQRSTUVWXYZ" "0123456789" "~!@#$%^&*()-=_+\\/?,.<>|{}[]`';:\" "; + static const uint8_t text_chars_size = sizeof text_chars - 1; // to avoid '\0' + std::string result; + + if (len < 1) + return result; + + result.resize(len); + char* result_buf = &result[0]; + uint8_t* rnd_indices = new uint8_t[len]; + crypto::generate_random_bytes(len, rnd_indices); + + size_t n = len / 4, i; + for (i = 0; i < n; ++i) + { + result_buf[4 * i + 0] = text_chars[rnd_indices[4 * i + 0] % text_chars_size]; + result_buf[4 * i + 1] = text_chars[rnd_indices[4 * i + 1] % text_chars_size]; + result_buf[4 * i + 2] = text_chars[rnd_indices[4 * i + 2] % text_chars_size]; + result_buf[4 * i + 3] = text_chars[rnd_indices[4 * i + 3] % text_chars_size]; + } + for (size_t j = i * 4; j < len; ++j) + { + result_buf[j] = text_chars[rnd_indices[j] % text_chars_size]; + } + + delete[] rnd_indices; + return result; + } +} bool random_state_manupulation_test(); bool random_evenness_test();