diff --git a/libraries/chain/CMakeLists.txt b/libraries/chain/CMakeLists.txt index 7e362a0528..8ebef9283c 100644 --- a/libraries/chain/CMakeLists.txt +++ b/libraries/chain/CMakeLists.txt @@ -106,7 +106,6 @@ add_library( eosio_chain wast_to_wasm.cpp wasm_interface.cpp - wasm_interface_collection.cpp wasm_eosio_validation.cpp wasm_eosio_injection.cpp wasm_config.cpp diff --git a/libraries/chain/apply_context.cpp b/libraries/chain/apply_context.cpp index 6dc0f9a1b6..d4a067feb5 100644 --- a/libraries/chain/apply_context.cpp +++ b/libraries/chain/apply_context.cpp @@ -3,7 +3,6 @@ #include #include #include -#include #include #include #include diff --git a/libraries/chain/controller.cpp b/libraries/chain/controller.cpp index 7760ecc01a..e4c6f89bb0 100644 --- a/libraries/chain/controller.cpp +++ b/libraries/chain/controller.cpp @@ -26,7 +26,6 @@ #include #include #include -#include #include #include @@ -258,7 +257,7 @@ struct controller_impl { #if defined(EOSIO_EOS_VM_RUNTIME_ENABLED) || defined(EOSIO_EOS_VM_JIT_RUNTIME_ENABLED) thread_local static vm::wasm_allocator wasm_alloc; // a copy for main thread and each read-only thread #endif - wasm_interface_collection wasm_if_collect; + wasm_interface wasmif; app_window_type app_window = app_window_type::write; typedef pair handler_key; @@ -319,7 +318,7 @@ struct controller_impl { chain_id( chain_id ), read_mode( cfg.read_mode ), thread_pool(), - wasm_if_collect( conf.wasm_runtime, conf.eosvmoc_tierup, db, conf.state_dir, conf.eosvmoc_config, !conf.profile_accounts.empty() ) + wasmif( conf.wasm_runtime, conf.eosvmoc_tierup, db, conf.state_dir, conf.eosvmoc_config, !conf.profile_accounts.empty() ) { fork_db.open( [this]( block_timestamp_type timestamp, const flat_set& cur_features, @@ -347,7 +346,7 @@ struct controller_impl { set_activation_handler(); self.irreversible_block.connect([this](const block_state_ptr& bsp) { - wasm_if_collect.current_lib(bsp->block_num); + wasmif.current_lib(bsp->block_num); }); @@ -2710,20 +2709,26 @@ struct controller_impl { #ifdef EOSIO_EOS_VM_OC_RUNTIME_ENABLED bool is_eos_vm_oc_enabled() const { - return wasm_if_collect.is_eos_vm_oc_enabled(); + return wasmif.is_eos_vm_oc_enabled(); } #endif + // Only called from read-only trx execution threads when producer_plugin + // starts them. Only OC requires initialize thread specific data. void init_thread_local_data() { - wasm_if_collect.init_thread_local_data(db, conf.state_dir, conf.eosvmoc_config, !conf.profile_accounts.empty()); +#ifdef EOSIO_EOS_VM_OC_RUNTIME_ENABLED + if ( is_eos_vm_oc_enabled() ) { + wasmif.init_thread_local_data(); + } +#endif } - wasm_interface_collection& get_wasm_interface() { - return wasm_if_collect; + wasm_interface& get_wasm_interface() { + return wasmif; } void code_block_num_last_used(const digest_type& code_hash, uint8_t vm_type, uint8_t vm_version, uint32_t block_num) { - wasm_if_collect.code_block_num_last_used(code_hash, vm_type, vm_version, block_num); + wasmif.code_block_num_last_used(code_hash, vm_type, vm_version, block_num); } block_state_ptr fork_db_head() const; @@ -3428,7 +3433,7 @@ const apply_handler* controller::find_apply_handler( account_name receiver, acco } return nullptr; } -wasm_interface_collection& controller::get_wasm_interface() { +wasm_interface& controller::get_wasm_interface() { return my->get_wasm_interface(); } diff --git a/libraries/chain/include/eosio/chain/controller.hpp b/libraries/chain/include/eosio/chain/controller.hpp index 5c16868f97..b86cba8a06 100644 --- a/libraries/chain/include/eosio/chain/controller.hpp +++ b/libraries/chain/include/eosio/chain/controller.hpp @@ -40,7 +40,6 @@ namespace eosio { namespace chain { class account_object; class deep_mind_handler; class subjective_billing; - class wasm_interface_collection; using resource_limits::resource_limits_manager; using apply_handler = std::function; using forked_branch_callback = std::function; @@ -344,7 +343,7 @@ namespace eosio { namespace chain { signal bad_alloc; const apply_handler* find_apply_handler( account_name contract, scope_name scope, action_name act )const; - wasm_interface_collection& get_wasm_interface(); + wasm_interface& get_wasm_interface(); static chain_id_type extract_chain_id(snapshot_reader& snapshot); diff --git a/libraries/chain/include/eosio/chain/wasm_interface.hpp b/libraries/chain/include/eosio/chain/wasm_interface.hpp index 7e67d28151..72f5cd3f23 100644 --- a/libraries/chain/include/eosio/chain/wasm_interface.hpp +++ b/libraries/chain/include/eosio/chain/wasm_interface.hpp @@ -46,12 +46,19 @@ namespace eosio { namespace chain { oc_none }; - wasm_interface(vm_type vm, const chainbase::database& d, const std::filesystem::path data_dir, const eosvmoc::config& eosvmoc_config, bool profile); + inline static bool test_disable_tierup = false; // set by unittests to test tierup failing + + wasm_interface(vm_type vm, vm_oc_enable eosvmoc_tierup, const chainbase::database& d, const std::filesystem::path data_dir, const eosvmoc::config& eosvmoc_config, bool profile); ~wasm_interface(); +#ifdef EOSIO_EOS_VM_OC_RUNTIME_ENABLED // initialize exec per thread void init_thread_local_data(); + // returns true if EOS VM OC is enabled + bool is_eos_vm_oc_enabled() const; +#endif + //call before dtor to skip what can be minutes of dtor overhead with some runtimes; can cause leaks void indicate_shutting_down(); @@ -61,15 +68,21 @@ namespace eosio { namespace chain { //indicate that a particular code probably won't be used after given block_num void code_block_num_last_used(const digest_type& code_hash, const uint8_t& vm_type, const uint8_t& vm_version, const uint32_t& block_num); - //indicate the current LIB. evicts old cache entries, each evicted entry is provided to callback - void current_lib(const uint32_t lib, const std::function& callback); + //indicate the current LIB. evicts old cache entries + void current_lib(const uint32_t lib); //Calls apply or error on a given code void apply(const digest_type& code_hash, const uint8_t& vm_type, const uint8_t& vm_version, apply_context& context); //Returns true if the code is cached bool is_code_cached(const digest_type& code_hash, const uint8_t& vm_type, const uint8_t& vm_version) const; + + // If substitute_apply is set, then apply calls it before doing anything else. If substitute_apply returns true, + // then apply returns immediately. Provided function must be multi-thread safe. + std::function substitute_apply; + private: + vm_oc_enable eosvmoc_tierup; unique_ptr my; }; diff --git a/libraries/chain/include/eosio/chain/wasm_interface_collection.hpp b/libraries/chain/include/eosio/chain/wasm_interface_collection.hpp deleted file mode 100644 index 4ee4ac7388..0000000000 --- a/libraries/chain/include/eosio/chain/wasm_interface_collection.hpp +++ /dev/null @@ -1,65 +0,0 @@ -#pragma once -#include -#include -#include -#include - -namespace eosio::chain { - - /** - * @class wasm_interface_collection manages the active wasm_interface to use for execution. - */ - class wasm_interface_collection { - public: - inline static bool test_disable_tierup = false; // set by unittests to test tierup failing - - wasm_interface_collection(wasm_interface::vm_type vm, wasm_interface::vm_oc_enable eosvmoc_tierup, - const chainbase::database& d, const std::filesystem::path& data_dir, - const eosvmoc::config& eosvmoc_config, bool profile); - - ~wasm_interface_collection(); - - void apply(const digest_type& code_hash, const uint8_t& vm_type, const uint8_t& vm_version, apply_context& context); - - // used for tests, only valid on main thread - bool is_code_cached(const digest_type& code_hash, const uint8_t& vm_type, const uint8_t& vm_version) { - EOS_ASSERT(is_on_main_thread(), wasm_execution_error, "is_code_cached called off the main thread"); - return wasmif.is_code_cached(code_hash, vm_type, vm_version); - } - - // update current lib of all wasm interfaces - void current_lib(const uint32_t lib); - - // only called from non-main threads (read-only trx execution threads) when producer_plugin starts them - void init_thread_local_data(const chainbase::database& d, const std::filesystem::path& data_dir, const eosvmoc::config& eosvmoc_config, bool profile); - -#ifdef EOSIO_EOS_VM_OC_RUNTIME_ENABLED - bool is_eos_vm_oc_enabled() const { - return ((eosvmoc_tierup != wasm_interface::vm_oc_enable::oc_none) || wasm_runtime == wasm_interface::vm_type::eos_vm_oc); - } -#endif - - void code_block_num_last_used(const digest_type& code_hash, uint8_t vm_type, uint8_t vm_version, uint32_t block_num); - - // If substitute_apply is set, then apply calls it before doing anything else. If substitute_apply returns true, - // then apply returns immediately. Provided function must be multi-thread safe. - std::function substitute_apply; - - private: - bool is_on_main_thread() { return main_thread_id == std::this_thread::get_id(); }; - - private: - const std::thread::id main_thread_id; - const wasm_interface::vm_type wasm_runtime; - const wasm_interface::vm_oc_enable eosvmoc_tierup; - - wasm_interface wasmif; // used by main thread - std::mutex threaded_wasmifs_mtx; - std::unordered_map> threaded_wasmifs; // one for each read-only thread, used by eos-vm and eos-vm-jit - -#ifdef EOSIO_EOS_VM_OC_RUNTIME_ENABLED - std::unique_ptr eosvmoc; // used by all threads -#endif - }; - -} // eosio::chain diff --git a/libraries/chain/include/eosio/chain/wasm_interface_private.hpp b/libraries/chain/include/eosio/chain/wasm_interface_private.hpp index e7ea5776e6..961b6dd27e 100644 --- a/libraries/chain/include/eosio/chain/wasm_interface_private.hpp +++ b/libraries/chain/include/eosio/chain/wasm_interface_private.hpp @@ -22,6 +22,8 @@ #include #include +#include + using namespace fc; using namespace eosio::chain::webassembly; using namespace IR; @@ -43,7 +45,31 @@ namespace eosio { namespace chain { struct by_hash; struct by_last_block_num; - wasm_interface_impl(wasm_interface::vm_type vm, const chainbase::database& d, +#ifdef EOSIO_EOS_VM_OC_RUNTIME_ENABLED +struct eosvmoc_tier { + // Called from main thread + eosvmoc_tier(const std::filesystem::path& d, const eosvmoc::config& c, const chainbase::database& db) + : cc(d, c, db) { + // Construct exec and mem for the main thread + exec = std::make_unique(cc); + mem = std::make_unique(wasm_constraints::maximum_linear_memory/wasm_constraints::wasm_page_size); + } + + // Called from read-only threads + void init_thread_local_data() { + exec = std::make_unique(cc); + mem = std::make_unique(eosvmoc::memory::sliced_pages_for_ro_thread); + } + + eosvmoc::code_cache_async cc; + + // Each thread requires its own exec and mem. Defined in wasm_interface.cpp + thread_local static std::unique_ptr exec; + thread_local static std::unique_ptr mem; +}; +#endif + + wasm_interface_impl(wasm_interface::vm_type vm, wasm_interface::vm_oc_enable eosvmoc_tierup, const chainbase::database& d, const std::filesystem::path data_dir, const eosvmoc::config& eosvmoc_config, bool profile) : db(d) , wasm_runtime_time(vm) @@ -66,16 +92,30 @@ namespace eosio { namespace chain { #endif if(!runtime_interface) EOS_THROW(wasm_exception, "${r} wasm runtime not supported on this platform and/or configuration", ("r", vm)); + +#ifdef EOSIO_EOS_VM_OC_RUNTIME_ENABLED + if(eosvmoc_tierup != wasm_interface::vm_oc_enable::oc_none) { + EOS_ASSERT(vm != wasm_interface::vm_type::eos_vm_oc, wasm_exception, "You can't use EOS VM OC as the base runtime when tier up is activated"); + eosvmoc = std::make_unique(data_dir, eosvmoc_config, d); + } +#endif } ~wasm_interface_impl() = default; bool is_code_cached(const digest_type& code_hash, const uint8_t& vm_type, const uint8_t& vm_version) const { + // This method is only called from tests; performance is not critical. + // No need for an additional check if we should lock or not. + std::lock_guard g(instantiation_cache_mutex); wasm_cache_index::iterator it = wasm_instantiation_cache.find( boost::make_tuple(code_hash, vm_type, vm_version) ); return it != wasm_instantiation_cache.end(); } void code_block_num_last_used(const digest_type& code_hash, const uint8_t& vm_type, const uint8_t& vm_version, const uint32_t& block_num) { + // The caller of this method apply_eosio_setcode has asserted that + // the transaction is not read-only, implying we are + // in write window. Read-only threads are not running. + // Safe to update the cache without locking. wasm_cache_index::iterator it = wasm_instantiation_cache.find(boost::make_tuple(code_hash, vm_type, vm_version)); if(it != wasm_instantiation_cache.end()) wasm_instantiation_cache.modify(it, [block_num](wasm_cache_entry& e) { @@ -84,48 +124,72 @@ namespace eosio { namespace chain { } // reports each code_hash and vm_version that will be erased to callback - void current_lib(uint32_t lib, const std::function& callback) { - //anything last used before or on the LIB can be evicted + void current_lib(uint32_t lib) { + // producer_plugin has asserted irreversible_block signal is called + // in write window. Read-only threads are not running. + // Safe to update the cache without locking. + // Anything last used before or on the LIB can be evicted. const auto first_it = wasm_instantiation_cache.get().begin(); const auto last_it = wasm_instantiation_cache.get().upper_bound(lib); - if (callback) { - for(auto it = first_it; it != last_it; it++) { - callback(it->code_hash, it->vm_version); - } - } +#ifdef EOSIO_EOS_VM_OC_RUNTIME_ENABLED + if(eosvmoc) for(auto it = first_it; it != last_it; it++) + eosvmoc->cc.free_code(it->code_hash, it->vm_version); +#endif wasm_instantiation_cache.get().erase(first_it, last_it); } - const std::unique_ptr& get_instantiated_module( const digest_type& code_hash, const uint8_t& vm_type, - const uint8_t& vm_version, transaction_context& trx_context ) +#ifdef EOSIO_EOS_VM_OC_RUNTIME_ENABLED + bool is_eos_vm_oc_enabled() const { + return (eosvmoc || wasm_runtime_time == wasm_interface::vm_type::eos_vm_oc); + } +#endif + + const std::unique_ptr& get_instantiated_module( + const digest_type& code_hash, + const uint8_t& vm_type, + const uint8_t& vm_version, + transaction_context& trx_context) { - wasm_cache_index::iterator it = wasm_instantiation_cache.find( - boost::make_tuple(code_hash, vm_type, vm_version) ); - const code_object* codeobject = nullptr; - if(it == wasm_instantiation_cache.end()) { - codeobject = &db.get(boost::make_tuple(code_hash, vm_type, vm_version)); - - it = wasm_instantiation_cache.emplace( wasm_interface_impl::wasm_cache_entry{ - .code_hash = code_hash, - .last_block_num_used = UINT32_MAX, - .module = nullptr, - .vm_type = vm_type, - .vm_version = vm_version - } ).first; + if (trx_context.control.is_write_window()) { + // When in write window (either read only threads are not enabled or + // they are not schedued to run), only main thread is processing + // transactions. No need to lock. + return get_or_build_instantiated_module(code_hash, vm_type, vm_version, trx_context); + } else { + std::lock_guard g(instantiation_cache_mutex); + return get_or_build_instantiated_module(code_hash, vm_type, vm_version, trx_context); } + } - if(!it->module) { - if(!codeobject) - codeobject = &db.get(boost::make_tuple(code_hash, vm_type, vm_version)); - - auto timer_pause = fc::make_scoped_exit([&](){ - trx_context.resume_billing_timer(); - }); - trx_context.pause_billing_timer(); - wasm_instantiation_cache.modify(it, [&](auto& c) { - c.module = runtime_interface->instantiate_module(codeobject->code.data(), codeobject->code.size(), code_hash, vm_type, vm_version); - }); + // Locked by the caller if required. + const std::unique_ptr& get_or_build_instantiated_module( + const digest_type& code_hash, + const uint8_t& vm_type, + const uint8_t& vm_version, + transaction_context& trx_context ) + { + wasm_cache_index::iterator it = wasm_instantiation_cache.find( boost::make_tuple(code_hash, vm_type, vm_version) ); + if (it != wasm_instantiation_cache.end()) { + // An instantiated module's module should never be null. + assert(it->module); + return it->module; } + + const code_object* codeobject = &db.get(boost::make_tuple(code_hash, vm_type, vm_version)); + it = wasm_instantiation_cache.emplace( wasm_interface_impl::wasm_cache_entry { + .code_hash = code_hash, + .last_block_num_used = UINT32_MAX, + .module = nullptr, + .vm_type = vm_type, + .vm_version = vm_version + } ).first; + auto timer_pause = fc::make_scoped_exit([&](){ + trx_context.resume_billing_timer(); + }); + trx_context.pause_billing_timer(); + wasm_instantiation_cache.modify(it, [&](auto& c) { + c.module = runtime_interface->instantiate_module(codeobject->code.data(), codeobject->code.size(), code_hash, vm_type, vm_version); + }); return it->module; } @@ -144,10 +208,15 @@ namespace eosio { namespace chain { ordered_non_unique, member> > > wasm_cache_index; + mutable std::mutex instantiation_cache_mutex; wasm_cache_index wasm_instantiation_cache; const chainbase::database& db; const wasm_interface::vm_type wasm_runtime_time; + +#ifdef EOSIO_EOS_VM_OC_RUNTIME_ENABLED + std::unique_ptr eosvmoc{nullptr}; // used by all threads +#endif }; } } // eosio::chain diff --git a/libraries/chain/include/eosio/chain/webassembly/eos-vm.hpp b/libraries/chain/include/eosio/chain/webassembly/eos-vm.hpp index 5a1a058878..4b182dcd41 100644 --- a/libraries/chain/include/eosio/chain/webassembly/eos-vm.hpp +++ b/libraries/chain/include/eosio/chain/webassembly/eos-vm.hpp @@ -49,8 +49,11 @@ class eos_vm_runtime : public eosio::chain::wasm_runtime_interface { private: // todo: managing this will get more complicated with sync calls; - eos_vm_backend_t* _bkend = nullptr; // non owning pointer to allow for immediate exit - context_t _exec_ctx; + // Each thread uses its own backend and exec context. + // Their constructors do not take any arguments; therefore their life time + // do not rely on others. Safe to be thread_local. + thread_local static eos_vm_backend_t _bkend; + thread_local static context_t _exec_ctx; template friend class eos_vm_instantiated_module; diff --git a/libraries/chain/wasm_interface.cpp b/libraries/chain/wasm_interface.cpp index abe014d946..0348157d03 100644 --- a/libraries/chain/wasm_interface.cpp +++ b/libraries/chain/wasm_interface.cpp @@ -32,15 +32,19 @@ namespace eosio { namespace chain { - wasm_interface::wasm_interface(vm_type vm, const chainbase::database& d, const std::filesystem::path data_dir, const eosvmoc::config& eosvmoc_config, bool profile) - : my( new wasm_interface_impl(vm, d, data_dir, eosvmoc_config, profile) ) {} + wasm_interface::wasm_interface(vm_type vm, vm_oc_enable eosvmoc_tierup, const chainbase::database& d, const std::filesystem::path data_dir, const eosvmoc::config& eosvmoc_config, bool profile) + : eosvmoc_tierup(eosvmoc_tierup), my( new wasm_interface_impl(vm, eosvmoc_tierup, d, data_dir, eosvmoc_config, profile) ) {} wasm_interface::~wasm_interface() {} #ifdef EOSIO_EOS_VM_OC_RUNTIME_ENABLED void wasm_interface::init_thread_local_data() { - if (my->wasm_runtime_time == wasm_interface::vm_type::eos_vm_oc && my->runtime_interface) + // OC tierup and OC runtime are mutually exclusive + if (my->eosvmoc) { + my->eosvmoc->init_thread_local_data(); + } else if (my->wasm_runtime_time == wasm_interface::vm_type::eos_vm_oc && my->runtime_interface) { my->runtime_interface->init_thread_local_data(); + } } #endif @@ -76,11 +80,39 @@ namespace eosio { namespace chain { my->code_block_num_last_used(code_hash, vm_type, vm_version, block_num); } - void wasm_interface::current_lib(const uint32_t lib, const std::function& callback) { - my->current_lib(lib, callback); + void wasm_interface::current_lib(const uint32_t lib) { + my->current_lib(lib); } void wasm_interface::apply( const digest_type& code_hash, const uint8_t& vm_type, const uint8_t& vm_version, apply_context& context ) { + if (substitute_apply && substitute_apply(code_hash, vm_type, vm_version, context)) + return; +#ifdef EOSIO_EOS_VM_OC_RUNTIME_ENABLED + if (my->eosvmoc && (eosvmoc_tierup == wasm_interface::vm_oc_enable::oc_all || context.should_use_eos_vm_oc())) { + const chain::eosvmoc::code_descriptor* cd = nullptr; + chain::eosvmoc::code_cache_base::get_cd_failure failure = chain::eosvmoc::code_cache_base::get_cd_failure::temporary; + try { + const bool high_priority = context.get_receiver().prefix() == chain::config::system_account_name; + cd = my->eosvmoc->cc.get_descriptor_for_code(high_priority, code_hash, vm_version, context.control.is_write_window(), failure); + if (test_disable_tierup) + cd = nullptr; + } catch (...) { + // swallow errors here, if EOS VM OC has gone in to the weeds we shouldn't bail: continue to try and run baseline + // In the future, consider moving bits of EOS VM that can fire exceptions and such out of this call path + static bool once_is_enough; + if (!once_is_enough) + elog("EOS VM OC has encountered an unexpected failure"); + once_is_enough = true; + } + if (cd) { + if (!context.is_applying_block()) // read_only_trx_test.py looks for this log statement + tlog("${a} speculatively executing ${h} with eos vm oc", ("a", context.get_receiver())("h", code_hash)); + my->eosvmoc->exec->execute(*cd, *my->eosvmoc->mem, context); + return; + } + } +#endif + my->get_instantiated_module(code_hash, vm_type, vm_version, context.trx_context)->apply(context); } @@ -88,9 +120,20 @@ namespace eosio { namespace chain { return my->is_code_cached(code_hash, vm_type, vm_version); } +#ifdef EOSIO_EOS_VM_OC_RUNTIME_ENABLED + bool wasm_interface::is_eos_vm_oc_enabled() const { + return my->is_eos_vm_oc_enabled(); + } +#endif + wasm_instantiated_module_interface::~wasm_instantiated_module_interface() = default; wasm_runtime_interface::~wasm_runtime_interface() = default; +#ifdef EOSIO_EOS_VM_OC_RUNTIME_ENABLED + thread_local std::unique_ptr wasm_interface_impl::eosvmoc_tier::exec{}; + thread_local std::unique_ptr wasm_interface_impl::eosvmoc_tier::mem{}; +#endif + std::istream& operator>>(std::istream& in, wasm_interface::vm_type& runtime) { std::string s; in >> s; diff --git a/libraries/chain/wasm_interface_collection.cpp b/libraries/chain/wasm_interface_collection.cpp deleted file mode 100644 index 0ea68397bf..0000000000 --- a/libraries/chain/wasm_interface_collection.cpp +++ /dev/null @@ -1,134 +0,0 @@ -#include -#ifdef EOSIO_EOS_VM_OC_RUNTIME_ENABLED -#include -#else -#define _REGISTER_EOSVMOC_INTRINSIC(CLS, MOD, METHOD, WASM_SIG, NAME, SIG) -#endif - -namespace eosio::chain { - -#ifdef EOSIO_EOS_VM_OC_RUNTIME_ENABLED -struct eosvmoc_tier { - // Called from main thread - eosvmoc_tier(const std::filesystem::path& d, const eosvmoc::config& c, const chainbase::database& db) - : cc(d, c, db) { - // Construct exec and mem for the main thread - exec = std::make_unique(cc); - mem = std::make_unique(wasm_constraints::maximum_linear_memory/wasm_constraints::wasm_page_size); - } - - // Called from read-only threads - void init_thread_local_data() { - exec = std::make_unique(cc); - mem = std::make_unique(eosvmoc::memory::sliced_pages_for_ro_thread); - } - - eosvmoc::code_cache_async cc; - - // Each thread requires its own exec and mem. - thread_local static std::unique_ptr exec; - thread_local static std::unique_ptr mem; -}; - -thread_local std::unique_ptr eosvmoc_tier::exec{}; -thread_local std::unique_ptr eosvmoc_tier::mem{}; -#endif - -wasm_interface_collection::wasm_interface_collection(wasm_interface::vm_type vm, wasm_interface::vm_oc_enable eosvmoc_tierup, - const chainbase::database& d, const std::filesystem::path& data_dir, - const eosvmoc::config& eosvmoc_config, bool profile) - : main_thread_id(std::this_thread::get_id()) - , wasm_runtime(vm) - , eosvmoc_tierup(eosvmoc_tierup) - , wasmif(vm, d, data_dir, eosvmoc_config, profile) { -#ifdef EOSIO_EOS_VM_OC_RUNTIME_ENABLED - if (eosvmoc_tierup != wasm_interface::vm_oc_enable::oc_none) { - EOS_ASSERT(vm != wasm_interface::vm_type::eos_vm_oc, wasm_exception, "You can't use EOS VM OC as the base runtime when tier up is activated"); - eosvmoc = std::make_unique(data_dir, eosvmoc_config, d); - } -#endif -} - -wasm_interface_collection::~wasm_interface_collection() = default; - -void wasm_interface_collection::apply(const digest_type& code_hash, const uint8_t& vm_type, const uint8_t& vm_version, apply_context& context) { - if (substitute_apply && substitute_apply(code_hash, vm_type, vm_version, context)) - return; -#ifdef EOSIO_EOS_VM_OC_RUNTIME_ENABLED - if (eosvmoc && (eosvmoc_tierup == wasm_interface::vm_oc_enable::oc_all || context.should_use_eos_vm_oc())) { - const chain::eosvmoc::code_descriptor* cd = nullptr; - chain::eosvmoc::code_cache_base::get_cd_failure failure = chain::eosvmoc::code_cache_base::get_cd_failure::temporary; - try { - const bool high_priority = context.get_receiver().prefix() == chain::config::system_account_name; - cd = eosvmoc->cc.get_descriptor_for_code(high_priority, code_hash, vm_version, context.control.is_write_window(), failure); - if (test_disable_tierup) - cd = nullptr; - } catch (...) { - // swallow errors here, if EOS VM OC has gone in to the weeds we shouldn't bail: continue to try and run baseline - // In the future, consider moving bits of EOS VM that can fire exceptions and such out of this call path - static bool once_is_enough; - if (!once_is_enough) - elog("EOS VM OC has encountered an unexpected failure"); - once_is_enough = true; - } - if (cd) { - if (!context.is_applying_block()) // read_only_trx_test.py looks for this log statement - tlog("${a} speculatively executing ${h} with eos vm oc", ("a", context.get_receiver())("h", code_hash)); - eosvmoc->exec->execute(*cd, *eosvmoc->mem, context); - return; - } - } -#endif - if (is_on_main_thread()) { - wasmif.apply(code_hash, vm_type, vm_version, context); - return; - } - threaded_wasmifs[std::this_thread::get_id()]->apply(code_hash, vm_type, vm_version, context); -} - -// update current lib of all wasm interfaces -void wasm_interface_collection::current_lib(const uint32_t lib) { - // producer_plugin has already asserted irreversible_block signal is called in write window - std::function cb{}; -#ifdef EOSIO_EOS_VM_OC_RUNTIME_ENABLED - if (eosvmoc) { - cb = [&](const digest_type& code_hash, uint8_t vm_version) { - eosvmoc->cc.free_code(code_hash, vm_version); - }; - } -#endif - wasmif.current_lib(lib, cb); - for (auto& w : threaded_wasmifs) { - w.second->current_lib(lib, cb); - } -} - -// only called from non-main threads (read-only trx execution threads) when producer_plugin starts them -void wasm_interface_collection::init_thread_local_data(const chainbase::database& d, const std::filesystem::path& data_dir, - const eosvmoc::config& eosvmoc_config, bool profile) { - EOS_ASSERT(!is_on_main_thread(), misc_exception, "init_thread_local_data called on the main thread"); -#ifdef EOSIO_EOS_VM_OC_RUNTIME_ENABLED - if (is_eos_vm_oc_enabled()) { - // EOSVMOC needs further initialization of its thread local data - if (eosvmoc) - eosvmoc->init_thread_local_data(); - wasmif.init_thread_local_data(); - } -#endif - - std::lock_guard g(threaded_wasmifs_mtx); - // Non-EOSVMOC needs a wasmif per thread - threaded_wasmifs[std::this_thread::get_id()] = std::make_unique(wasm_runtime, d, data_dir, eosvmoc_config, profile); -} - -void wasm_interface_collection::code_block_num_last_used(const digest_type& code_hash, uint8_t vm_type, uint8_t vm_version, uint32_t block_num) { - // The caller of this function apply_eosio_setcode has already asserted that - // the transaction is not a read-only trx, which implies we are - // in write window. Safe to call threaded_wasmifs's code_block_num_last_used - wasmif.code_block_num_last_used(code_hash, vm_type, vm_version, block_num); - for (auto& w : threaded_wasmifs) { - w.second->code_block_num_last_used(code_hash, vm_type, vm_version, block_num); - } -} - -} // namespace eosio::chain diff --git a/libraries/chain/webassembly/runtimes/eos-vm.cpp b/libraries/chain/webassembly/runtimes/eos-vm.cpp index d0eaea4b32..e1692d335b 100644 --- a/libraries/chain/webassembly/runtimes/eos-vm.cpp +++ b/libraries/chain/webassembly/runtimes/eos-vm.cpp @@ -129,14 +129,19 @@ class eos_vm_instantiated_module : public wasm_instantiated_module_interface { _instantiated_module(std::move(mod)) {} void apply(apply_context& context) override { - // Reset execution context (reused per thread) + // set up backend to share the compiled mod in the instantiated + // module of the contract + _runtime->_bkend.share(*_instantiated_module); + // set exec ctx's mod to instantiated module's mod _runtime->_exec_ctx.set_module(&(_instantiated_module->get_module())); - _instantiated_module->set_context(&_runtime->_exec_ctx); - _instantiated_module->reset_max_call_depth(); - _instantiated_module->reset_max_pages(); + // link exe ctx to backend + _runtime->_bkend.set_context(&_runtime->_exec_ctx); + // set max_call_depth and max_pages to original values + _runtime->_bkend.reset_max_call_depth(); + _runtime->_bkend.reset_max_pages(); + // set wasm allocator per apply data + _runtime->_bkend.set_wasm_allocator(&context.control.get_wasm_allocator()); - _instantiated_module->set_wasm_allocator(&context.control.get_wasm_allocator()); - _runtime->_bkend = _instantiated_module.get(); apply_options opts; if(context.control.is_builtin_activated(builtin_protocol_feature_t::configurable_wasm_limits)) { const wasm_config& config = context.control.get_global_properties().wasm_configuration; @@ -144,8 +149,8 @@ class eos_vm_instantiated_module : public wasm_instantiated_module_interface { } auto fn = [&]() { eosio::chain::webassembly::interface iface(context); - _runtime->_bkend->initialize(&iface, opts); - _runtime->_bkend->call( + _runtime->_bkend.initialize(&iface, opts); + _runtime->_bkend.call( iface, "env", "apply", context.get_receiver().to_uint64_t(), context.get_action().account.to_uint64_t(), @@ -153,7 +158,7 @@ class eos_vm_instantiated_module : public wasm_instantiated_module_interface { }; try { checktime_watchdog wd(context.trx_context.transaction_timer); - _runtime->_bkend->timed_run(wd, fn); + _runtime->_bkend.timed_run(wd, fn); } catch(eosio::vm::timeout_exception&) { context.trx_context.checktime(); } catch(eosio::vm::wasm_memory_exception& e) { @@ -161,7 +166,6 @@ class eos_vm_instantiated_module : public wasm_instantiated_module_interface { } catch(eosio::vm::exception& e) { FC_THROW_EXCEPTION(wasm_execution_error, "eos-vm system failure"); } - _runtime->_bkend = nullptr; } private: @@ -282,6 +286,10 @@ std::unique_ptr eos_vm_profile_runtime::inst } #endif +template +thread_local eos_vm_runtime::context_t eos_vm_runtime::_exec_ctx; +template +thread_local eos_vm_backend_t eos_vm_runtime::_bkend; } template diff --git a/libraries/eos-vm b/libraries/eos-vm index 74dd3f0c5e..b06ac3d4c1 160000 --- a/libraries/eos-vm +++ b/libraries/eos-vm @@ -1 +1 @@ -Subproject commit 74dd3f0c5e621c4e22b543b0f1aa2539a516c46f +Subproject commit b06ac3d4c171cfd0a0f8fd74752e4eab35f60cb0 diff --git a/libraries/libfc/CMakeLists.txt b/libraries/libfc/CMakeLists.txt index 6d99ab9f5a..13e13eb477 100644 --- a/libraries/libfc/CMakeLists.txt +++ b/libraries/libfc/CMakeLists.txt @@ -106,7 +106,7 @@ find_package(ZLIB REQUIRED) target_include_directories(fc PUBLIC include) # try and make this very clear that this json parser is intended only for webauthn parsing.. -set_source_files_properties(src/crypto/elliptic_webauthn.cpp PROPERTIES COMPILE_FLAGS "-I${CMAKE_CURRENT_SOURCE_DIR}/include/fc/crypto/webauthn_json/include") +set_source_files_properties(src/crypto/elliptic_webauthn.cpp PROPERTIES INCLUDE_DIRECTORIES "${CMAKE_CURRENT_SOURCE_DIR}/include/fc/crypto/webauthn_json/include") if(WIN32) target_link_libraries( fc PUBLIC ws2_32 mswsock userenv ) diff --git a/libraries/libfc/include/fc/io/cfile.hpp b/libraries/libfc/include/fc/io/cfile.hpp index c09adf894d..7e79b59942 100644 --- a/libraries/libfc/include/fc/io/cfile.hpp +++ b/libraries/libfc/include/fc/io/cfile.hpp @@ -19,7 +19,11 @@ namespace fc { namespace detail { - using unique_file = std::unique_ptr; + inline void close_file(FILE* f) noexcept { + fclose(f); + } + + using unique_file = std::unique_ptr; } class cfile_datastream; @@ -32,7 +36,7 @@ class cfile { friend class temp_cfile; public: cfile() - : _file(nullptr, &fclose) + : _file(nullptr, &detail::close_file) {} cfile(cfile&& other) diff --git a/libraries/libfc/test/crypto/test_modular_arithmetic.cpp b/libraries/libfc/test/crypto/test_modular_arithmetic.cpp index f0bf5bd4f9..c46f1b5fd5 100644 --- a/libraries/libfc/test/crypto/test_modular_arithmetic.cpp +++ b/libraries/libfc/test/crypto/test_modular_arithmetic.cpp @@ -118,6 +118,838 @@ BOOST_AUTO_TEST_CASE(modexp) try { } FC_LOG_AND_RETHROW(); +BOOST_AUTO_TEST_CASE(modexp_boringssl_vectors) try { + struct modexp_test_params { + std::string ModExp; + std::string A; + std::string E; + std::string M; + }; + + const std::vector tests = { + // Regression test for carry propagation bug in sqr8x_reduction. + { + .ModExp = "19324b647d967d644b3219", + .A = "050505050505", + .E = "02", + .M = "414141414141414141414127414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001" + }, + // Cover the E = 0 case for small numbers. + { + .ModExp = "01", + .A = "086b49", + .E = "00", + .M = "30d26ecb" + }, + { + .ModExp = "00", + .A = "00", + .E = "00", + .M = "01" + }, + { + .ModExp = "208f8aa0", + .A = "086b49", + .E = "02", + .M = "30d26ecb" + }, + { + .ModExp = "27308229", + .A = "017591bb", + .E = "06", + .M = "30d26ecb" + }, + { + .ModExp = "2bdf498f", + .A = "21292626", + .E = "0d", + .M = "30d26ecb" + }, + { + .ModExp = "11317167", + .A = "04a655df24", + .E = "10", + .M = "30d26ecb" + }, + { + .ModExp = "02e1b88e", + .A = "da6b761a86", + .E = "35", + .M = "30d26ecb" + }, + { + .ModExp = "20a12ec3", + .A = "0ea811", + .E = "02", + .M = "23bc042f" + }, + { + .ModExp = "c42ced", + .A = "01011a6a", + .E = "04", + .M = "23bc042f" + }, + { + .ModExp = "04637d79", + .A = "28d9a601", + .E = "08", + .M = "23bc042f" + }, + { + .ModExp = "20e5669b", + .A = "072fe6bc20", + .E = "11", + .M = "23bc042f" + }, + { + .ModExp = "142ab9e3", + .A = "9a07b9363c", + .E = "29", + .M = "23bc042f" + }, + { + .ModExp = "14c64646", + .A = "0822df", + .E = "03", + .M = "30915765" + }, + { + .ModExp = "160e35a2", + .A = "015ea542", + .E = "05", + .M = "30915765" + }, + { + .ModExp = "2f23a488", + .A = "34d2e02e", + .E = "0e", + .M = "30915765" + }, + { + .ModExp = "28e67f93", + .A = "0636a32703", + .E = "14", + .M = "30915765" + }, + { + .ModExp = "29bfeaa5", + .A = "c8646998e6", + .E = "2c", + .M = "30915765" + }, + { + .ModExp = "30959e22", + .A = "081dad", + .E = "03", + .M = "326dd68d" + }, + { + .ModExp = "1a1da4fa", + .A = "0116adb9", + .E = "05", + .M = "326dd68d" + }, + { + .ModExp = "272bf0d8", + .A = "2d21ef08", + .E = "08", + .M = "326dd68d" + }, + { + .ModExp = "29f5054b", + .A = "076989850a", + .E = "16", + .M = "326dd68d" + }, + { + .ModExp = "0e6c7b77", + .A = "b88ee70d2a", + .E = "3e", + .M = "326dd68d" + }, + { + .ModExp = "369605e1", + .A = "0cf26f", + .E = "02", + .M = "3ce082eb" + }, + { + .ModExp = "168a3c5d", + .A = "01f82caf", + .E = "05", + .M = "3ce082eb" + }, + { + .ModExp = "125c4bb8", + .A = "2e9c4c07", + .E = "09", + .M = "3ce082eb" + }, + { + .ModExp = "1c5fe761", + .A = "0523ab37f1", + .E = "14", + .M = "3ce082eb" + }, + { + .ModExp = "21703009", + .A = "dc832165e8", + .E = "20", + .M = "3ce082eb" + }, + { + .ModExp = "01228d1e", + .A = "0a5555", + .E = "03", + .M = "24665b27" + }, + { + .ModExp = "05226af4", + .A = "01077bd6", + .E = "04", + .M = "24665b27" + }, + { + .ModExp = "1b14eac1", + .A = "2db3a834", + .E = "0f", + .M = "24665b27" + }, + { + .ModExp = "161727bc", + .A = "06bd962cb6", + .E = "19", + .M = "24665b27" + }, + { + .ModExp = "10d61d0d", + .A = "c10caed407", + .E = "28", + .M = "24665b27" + }, + { + .ModExp = "233da406", + .A = "0b125f", + .E = "03", + .M = "33509981" + }, + { + .ModExp = "24032799", + .A = "01656b7c", + .E = "06", + .M = "33509981" + }, + { + .ModExp = "129ecebe", + .A = "2e671504", + .E = "0a", + .M = "33509981" + }, + { + .ModExp = "20c20bac", + .A = "04d7a2de44", + .E = "1f", + .M = "33509981" + }, + { + .ModExp = "2e3ce9d3", + .A = "c53b3def4d", + .E = "31", + .M = "33509981" + }, + { + .ModExp = "12fadfd6", + .A = "0b4cf8", + .E = "02", + .M = "36e9d4ae" + }, + { + .ModExp = "0457ac85", + .A = "01b1c7e9", + .E = "07", + .M = "36e9d4ae" + }, + { + .ModExp = "31debef4", + .A = "3a973028", + .E = "0d", + .M = "36e9d4ae" + }, + { + .ModExp = "2333ad93", + .A = "0552b97c45", + .E = "11", + .M = "36e9d4ae" + }, + { + .ModExp = "099ba1fb", + .A = "8bfb949cbb", + .E = "28", + .M = "36e9d4ae" + }, + { + .ModExp = "27b691de", + .A = "093492", + .E = "03", + .M = "298fdb16" + }, + { + .ModExp = "03c2b70f", + .A = "014e7b0d", + .E = "04", + .M = "298fdb16" + }, + { + .ModExp = "1486cda7", + .A = "29acff81", + .E = "0c", + .M = "298fdb16" + }, + { + .ModExp = "11725275", + .A = "0507489205", + .E = "13", + .M = "298fdb16" + }, + { + .ModExp = "24d14627", + .A = "e71c55606d", + .E = "35", + .M = "298fdb16" + }, + { + .ModExp = "222b8d14", + .A = "09b1a0", + .E = "03", + .M = "3db59d12" + }, + { + .ModExp = "3b8bd47d", + .A = "013f4e8d", + .E = "07", + .M = "3db59d12" + }, + { + .ModExp = "17e72356", + .A = "334774ce", + .E = "0a", + .M = "3db59d12" + }, + { + .ModExp = "306447ca", + .A = "047079ddd2", + .E = "12", + .M = "3db59d12" + }, + { + .ModExp = "090bef3b", + .A = "a75d62616d", + .E = "37", + .M = "3db59d12" + }, + { + .ModExp = "01", + .A = "cddd44f47e84b3276cc36a5c0d742cc703e61c4756168601fbb1b6eb598c161019562344dd56ab6f603d920a12c360b285e6496a3605a2f8d691c3598233ee9366b5f2692554893bdeb67b7bdaf35ab7273ac593145e26bed82c70ba5793bf4bc5cac4c80b01785d1496beede493806e4f4aa89fd8d41de80dd6d0a3e2742678", + .E = "00", + .M = "c95943186c7567fe8cd1bb4f07e7c659475fd9f38217571af20dfe7e4666d86286bc5b2bb013197f9b1c452c69a95bb7e450cf6e45d46e452282d5d2826978e06c52c7ca204869e8d1b1fac4911e3aef92c7b2d7551ebd8c6fe0365fad49e275cc2949a124385cadc4ace24671c4fe86a849de07c6fafacb312f55e9f3c79dcb" + }, + { + .ModExp = "00", + .A = "00", + .E = "8de689aef79eba6b20d7debb8d146541348df2f259dff6c3bfabf5517c8caf0473866a03ddbd03fc354bb00beda35e67f342d684896bf8dbb79238a6929692b1a87f58a2dcba596fe1a0514e3019baffe1b580fc810bd9774c00ab0f37af78619b30f273e3bfb95daac34e74566f84bb8809be7650dec75a20be61b4f904ed4e", + .M = "c95943186c7567fe8cd1bb4f07e7c659475fd9f38217571af20dfe7e4666d86286bc5b2bb013197f9b1c452c69a95bb7e450cf6e45d46e452282d5d2826978e06c52c7ca204869e8d1b1fac4911e3aef92c7b2d7551ebd8c6fe0365fad49e275cc2949a124385cadc4ace24671c4fe86a849de07c6fafacb312f55e9f3c79dcb" + }, + { + .ModExp = "5150fb769d5c5d341aaf56639a7bcc77c415fe46439938a2190283409692f29cd080bfe3433005d98d24718a03a3553c8560c5e9c8ed0f53b8945eb18290e1c1a83d919302510f66dd89b58acc2de79ad54b8a30d3e1019d4d222556beefca0821b094ecf104b5e4cfce69d2d520d2abf54f3e393d25ed3d27e8c2e3ca2e5ff9", + .A = "ead8c5a451541c50cab74de530c89376d9a55c723e0cac3c84b25f0093c08a2961e49ab48966361c42c9f99111587252d98395b76788400d75c66ef208ea2767a28d6f8dc3a859f39c95765d57f139e7fc14f47c908c62df051e7216d379f52028843b4d82ef49133cce8fe671ae179423ac8da5be43b01caaf425cd969300cd", + .E = "8de689aef79eba6b20d7debb8d146541348df2f259dff6c3bfabf5517c8caf0473866a03ddbd03fc354bb00beda35e67f342d684896bf8dbb79238a6929692b1a87f58a2dcba596fe1a0514e3019baffe1b580fc810bd9774c00ab0f37af78619b30f273e3bfb95daac34e74566f84bb8809be7650dec75a20be61b4f904ed4e", + .M = "c95943186c7567fe8cd1bb4f07e7c659475fd9f38217571af20dfe7e4666d86286bc5b2bb013197f9b1c452c69a95bb7e450cf6e45d46e452282d5d2826978e06c52c7ca204869e8d1b1fac4911e3aef92c7b2d7551ebd8c6fe0365fad49e275cc2949a124385cadc4ace24671c4fe86a849de07c6fafacb312f55e9f3c79dcb" + }, + { + .ModExp = "01", + .A = "935561297d1d90255aef891e2e30aa09935409de3d4a5abc340ac9a9b7dce33e9f5ce407f3a67ec30e0dc30481070823f8542463e46828d9cafb672a506d6753688cbad3d2761079f770c726c0b957071a30876c4d448e884b647833befbcd6b582787bf769d63cf55e68c7b869a0b86374f8920516cf5d528f348b6057450a1", + .E = "00", + .M = "dcc24236a1bb94c71d9ec162a6aa4697b932717e82b667cad08b6bd1bbcbddf7cd167b7458de2b0b780486b39574e749d6405f9ede774a021d6b547271523e9e84a6fdd3a98315607ccf93356f54daa9c75e1e311e1672d0dc163be13f9ed6762f7dd301f5b0a1bb2398b608f40ac357ae34fc8a87d4fef3b961cbdb806d9061" + }, + { + .ModExp = "00", + .A = "00", + .E = "bb552be12c02ae8b9e90c8beb5689ffefe3378d2c30f12a6d14496250ecce30317c642857535a741642c3df689a8d71a276d247ed482b07b50135357da6143ac2f5c74f6c739c5ff6ada21e1ab35439f6445a1019d6b607950bffb0357c6009a2bfc88cd7f4f883dc591d4eb45b1d787e85aba5c10ee4fe05ea47bf556aec94d", + .M = "dcc24236a1bb94c71d9ec162a6aa4697b932717e82b667cad08b6bd1bbcbddf7cd167b7458de2b0b780486b39574e749d6405f9ede774a021d6b547271523e9e84a6fdd3a98315607ccf93356f54daa9c75e1e311e1672d0dc163be13f9ed6762f7dd301f5b0a1bb2398b608f40ac357ae34fc8a87d4fef3b961cbdb806d9061" + }, + { + .ModExp = "bbad67352704a6321809f742826bf3d1c31c0ad057bf81432abeb30dc9913c896c03e69eb1cde6b78ffcb320c4625bd38ef23a08d6c64dc86aec951b72d74b097e209ce63092959894614e3865a6153ec0ff6fda639e44071a33763f6b18edc1c22094c3f844f04a86d414c4cb618e9812991c61289360c7ba60f190f75038d0", + .A = "855144760f2be2f2038d8ff628f03a902ae2e07736f2695ec980f84a1781665ab65e2b4e53d31856f431a32fd58d8a7727acee54cc54a62161b035c0293714ca294e2161ea4a48660bf084b885f504ad23ea338030460310bd19186be9030ab5136f09fe6a9223962bce385aaaf9c39fe6ed6d005fa96163fe15cdfa08fc914d", + .E = "bb552be12c02ae8b9e90c8beb5689ffefe3378d2c30f12a6d14496250ecce30317c642857535a741642c3df689a8d71a276d247ed482b07b50135357da6143ac2f5c74f6c739c5ff6ada21e1ab35439f6445a1019d6b607950bffb0357c6009a2bfc88cd7f4f883dc591d4eb45b1d787e85aba5c10ee4fe05ea47bf556aec94d", + .M = "dcc24236a1bb94c71d9ec162a6aa4697b932717e82b667cad08b6bd1bbcbddf7cd167b7458de2b0b780486b39574e749d6405f9ede774a021d6b547271523e9e84a6fdd3a98315607ccf93356f54daa9c75e1e311e1672d0dc163be13f9ed6762f7dd301f5b0a1bb2398b608f40ac357ae34fc8a87d4fef3b961cbdb806d9061" + }, + { + .ModExp = "01", + .A = "9d92629c1ab181c50c31619e8acd0d235a1f5fc7a0bef4d4fd54b4f1968d45921f8522efe88e69c6c14c576c564592b9feb00d1554b88b038934eaf4a8ce81a2582732387490181ef158360c8b2d9ccb326ffe043f776a50cb8202837f08ca743b562eefa007150ab7012c341b16248478d4775c02ad71ea13d5e82b71e2d600", + .E = "00", + .M = "cd607549668469b792f495c141e500871880b0611c8004293a561ec7f9ab6561f8a9b90872742386adafb5cd1890e8204ae12aec529cca0a9e382c96439137f09de9973b12c8492c62847e107deabb7dd946ffbb9d0ac73b462c481092bd65326a17f21d8d6527c47a5dba50aaa20c7048b8788a49eb3ea5f29bd5cfce24eb3b" + }, + { + .ModExp = "00", + .A = "00", + .E = "9f43dcb641f3ecf4dbc97450f2bdf3b7ec6a2f3e8e96bb1df2bf34b8d2d78e1a9018d04d960ffd0e932cfc60d3b9b923e3f9f29b3f3d61cae3a9f7245078143475c7fcb896ff200f7d94c4f2708bb42750e37c185a31c876814e4f06a00771707654e1da2fb69c16b6500b16385e3b933e2276ad3569977473f699b1c7926c3b", + .M = "cd607549668469b792f495c141e500871880b0611c8004293a561ec7f9ab6561f8a9b90872742386adafb5cd1890e8204ae12aec529cca0a9e382c96439137f09de9973b12c8492c62847e107deabb7dd946ffbb9d0ac73b462c481092bd65326a17f21d8d6527c47a5dba50aaa20c7048b8788a49eb3ea5f29bd5cfce24eb3b" + }, + { + .ModExp = "24eaead5b57883c2f454928f8edd470a344bfe07a953194f7d635d705ef13ddfc64140c8ad6f363d4c828e7c7891a6b6d4df37335de4552c319dafd1c06d1f743240082a3535df4da1475d3eea3fead20e40815fd5a0876c881c162ab65a1eda494280c258901ca953d1d039a998bf0e9aa09273bbef4865f3054663b72d75ff", + .A = "a31618b4532f53729ba22efb2221432fab1dbb70853d6a1159b42fd19fc949965c709b209de106a652aa422d88922ce51dae47f7f6deaf0055202e13db79ee84fc3d3c6f4c003ef96597c49d6895fa53c22ac9e4819f7048146b5272f6279424fdb389819a0b251c823c76f4bebf4f1246de455aafe82a0d34454f5039e90839", + .E = "9f43dcb641f3ecf4dbc97450f2bdf3b7ec6a2f3e8e96bb1df2bf34b8d2d78e1a9018d04d960ffd0e932cfc60d3b9b923e3f9f29b3f3d61cae3a9f7245078143475c7fcb896ff200f7d94c4f2708bb42750e37c185a31c876814e4f06a00771707654e1da2fb69c16b6500b16385e3b933e2276ad3569977473f699b1c7926c3b", + .M = "cd607549668469b792f495c141e500871880b0611c8004293a561ec7f9ab6561f8a9b90872742386adafb5cd1890e8204ae12aec529cca0a9e382c96439137f09de9973b12c8492c62847e107deabb7dd946ffbb9d0ac73b462c481092bd65326a17f21d8d6527c47a5dba50aaa20c7048b8788a49eb3ea5f29bd5cfce24eb3b" + }, + { + .ModExp = "01", + .A = "a8558e7f455b27c0c46d7d0862eb409cdefbeca945e0284b5bf425b7ac0f3d316bc365594cc1639decffc621214d61479bc75135120d4ac09ea8b742ad7ec1822091b62b1c6f564fe5e2f4f5b7def92cbaaa9a898549207ab01b91c2324fbd306a87f7d6379b6fb6493c5fca76729767f136120da9c90bdc7d364f7d242d5acc", + .E = "00", + .M = "88f3c87ac5e3272a21b8a858da640d6939fb8113a95412c38663a0f352686d69a5d7927e60b484b9fcb8ef12978fe25ff2ebc9b61c5450e04222ef20ba3cbbdc5ec45581ce0f58e10be7bb9de7fa08752303a7a1db23b2ac9c6692ec63bf09ecd6639e06c5491ba568ea886620d71da32d329615f0e1443a75d09ae35b8a2d7f" + }, + { + .ModExp = "00", + .A = "00", + .E = "a5524b41dfc6b570df1d8f6633ac7777c1131abe3a99c6166b0d29d3b8883c41b00a0c53cdd6f42820bf05c810b6ec53e77a8c1b9344ea0c91d4f410a2f204c369f3db33bf8c88217fc2cf802a9d9bce8119242d8e781875b85431be170076498c0963574ee423551aec9557e2fc672ab1ab5d0cbb1c400535df9481e7934d8f", + .M = "88f3c87ac5e3272a21b8a858da640d6939fb8113a95412c38663a0f352686d69a5d7927e60b484b9fcb8ef12978fe25ff2ebc9b61c5450e04222ef20ba3cbbdc5ec45581ce0f58e10be7bb9de7fa08752303a7a1db23b2ac9c6692ec63bf09ecd6639e06c5491ba568ea886620d71da32d329615f0e1443a75d09ae35b8a2d7f" + }, + { + .ModExp = "292f0b39ca0f1c850b1a00cffd2d54924fcd5fc7e7504c9d593e6c0ff74760b1f4bdd81679fe06c50248336f3108c593fa111072ee87d0fcc89a63243a1dc89044503663eee9bc18f51c3e0193d9108303e12ac90ff78f6ec752a4386af09c42db524a7cbe9a3d4fcccd56c34d283bcc9debc17158b5fe8df0c1888a9841bf8f", + .A = "b4fde2908745ff92cc5826a27dcfdda09e8fffee681844fa4c7f1354d946d5d84e0e0c7a4a4cb20943d9c73dd707ca47d796945d6f6b55933b615e2c522f5dfc33e0652917b4809bab86f4fa56b32b746c177764895492d0a6a699812b2827fe701d40ef7effd78ea8efe1cac15ff74a295a09614bf04cae1a5017872ba22efe", + .E = "a5524b41dfc6b570df1d8f6633ac7777c1131abe3a99c6166b0d29d3b8883c41b00a0c53cdd6f42820bf05c810b6ec53e77a8c1b9344ea0c91d4f410a2f204c369f3db33bf8c88217fc2cf802a9d9bce8119242d8e781875b85431be170076498c0963574ee423551aec9557e2fc672ab1ab5d0cbb1c400535df9481e7934d8f", + .M = "88f3c87ac5e3272a21b8a858da640d6939fb8113a95412c38663a0f352686d69a5d7927e60b484b9fcb8ef12978fe25ff2ebc9b61c5450e04222ef20ba3cbbdc5ec45581ce0f58e10be7bb9de7fa08752303a7a1db23b2ac9c6692ec63bf09ecd6639e06c5491ba568ea886620d71da32d329615f0e1443a75d09ae35b8a2d7f" + }, + { + .ModExp = "01", + .A = "e2845c572b46496ac158a731f612fd40ef626fa7134755c25b1b7614f4d7b29164e6142ddb7985e4c7ebc575855ff901e95927fe98a5aea2ad3a4720c75782323bea1518b2c57790f44efd9411be4e95b3896bad1e73c59658290b309e5a7eb5ef8be08125063e57336b80f17eacee88966d12bbaaa15a25929c82e027cf696f", + .E = "00", + .M = "cf0dee80177869a532f0c6c3a0bda3aad79bdb6b70b6c227b32d75c26e394a90c1f2a6c2bb841ba9f6556b15654a79d8b1dd0c90709a093497bf40be0807cdbb378a74de5893c25067224d3ea8d37387ed6c4a981138853cb89caa9ce6cd0f6a1e95de24d558e90960f93844db4d01e372650350d45a9d34a36042b4d4b9e78d" + }, + { + .ModExp = "00", + .A = "00", + .E = "a55703a72ca3f6074b939ed3d748196a684a3c8e411c2b39a9beb98993b6eb7ea3fa16f41bc5b5c3710b91c0fc74a8072793052f872f61695db3a2df872eaa427a110f1a8d568c85d58bd350d0df8eced7a10be80f7567360c1a8047b9c44aa2967cd0d9dd2caea2c1492358c2db4f0214da343fdf2e34272865dc5c63be2ae4", + .M = "cf0dee80177869a532f0c6c3a0bda3aad79bdb6b70b6c227b32d75c26e394a90c1f2a6c2bb841ba9f6556b15654a79d8b1dd0c90709a093497bf40be0807cdbb378a74de5893c25067224d3ea8d37387ed6c4a981138853cb89caa9ce6cd0f6a1e95de24d558e90960f93844db4d01e372650350d45a9d34a36042b4d4b9e78d" + }, + { + .ModExp = "c90e4c69df92e26549b016950b59080947f5403430698e128477782480dd70be96bed2b9042dd8c708eb432e02710555b97af11ce6fa9b53395022851c32d1f53f04237fb0763563b440ca6e81a50d909d907d9c26b7d3c420dbf88f7dadd488666848135f8cdc608dcfb0691989289fb54379c2e84c262f9765f68c012ca1b9", + .A = "882ea1b9b6c79a3b1bdfd284658cb6227ad825e0178cab713c7413c2ec34f03cfaec470c4f5c521f5e9899a2123878ff0f5b36a4196c08ad1b04d03746c4bfb5d126f5eefbfe172627d6732710a8ac8890cedbd4fdef69a19f2b3253a5aa0e5dd5484f72d59b17bdd1dad3db209a3ab839368ed3975069685911d7b35e41a9e6", + .E = "a55703a72ca3f6074b939ed3d748196a684a3c8e411c2b39a9beb98993b6eb7ea3fa16f41bc5b5c3710b91c0fc74a8072793052f872f61695db3a2df872eaa427a110f1a8d568c85d58bd350d0df8eced7a10be80f7567360c1a8047b9c44aa2967cd0d9dd2caea2c1492358c2db4f0214da343fdf2e34272865dc5c63be2ae4", + .M = "cf0dee80177869a532f0c6c3a0bda3aad79bdb6b70b6c227b32d75c26e394a90c1f2a6c2bb841ba9f6556b15654a79d8b1dd0c90709a093497bf40be0807cdbb378a74de5893c25067224d3ea8d37387ed6c4a981138853cb89caa9ce6cd0f6a1e95de24d558e90960f93844db4d01e372650350d45a9d34a36042b4d4b9e78d" + }, + { + .ModExp = "01", + .A = "d7a99e65b8af86b1c51d851f0447e43cd4f343cb0ada7236283e69aa7ebd383826acc9809e5dbc4002d0f2430022cb026458189db3805ce2de1142a31ba71a6c064ab51f0059eb4b931b8bcbaef023c38d57aa5f3e14f5df77e547fc028702071b58bd57338be1e1e4f98d3553484e4de359cefa29c5f58d3fa5d823f389dbef", + .E = "00", + .M = "8315dacf124bd473c578946347e83d1b20c750a7d9533d6215591be40bc78bcca77821f8c8f95375bbd6372515ada63d22bed2fa49bd6fabb0040c538d08db25b09d2fda02a93ab086cd1c27df93c37ee9c6a0527d089179b8f92b5dc3acf5ef1c75906fb80b03f5c2442a7a4088640f66376575ecfa4c697c1a571397ee5a0d" + }, + { + .ModExp = "00", + .A = "00", + .E = "95793fe33696f53e37498b2b65aaf27079e27acf1da97dda2c3e0803e8a02139f574e04ee03f7d1ddd029f528e3f3644515ad6f10f0beac2767f23d9cd8a8b9b6c6e376e36b64a0ae2711d7d31a5a75011641935b503110edbefe9f0ff2da27b5c5f6bb8cc151fdc86f67191bb99160c6cacc86ca368d5bdfafd3f3ff5161b1e", + .M = "8315dacf124bd473c578946347e83d1b20c750a7d9533d6215591be40bc78bcca77821f8c8f95375bbd6372515ada63d22bed2fa49bd6fabb0040c538d08db25b09d2fda02a93ab086cd1c27df93c37ee9c6a0527d089179b8f92b5dc3acf5ef1c75906fb80b03f5c2442a7a4088640f66376575ecfa4c697c1a571397ee5a0d" + }, + { + .ModExp = "186c50ae259aa0fd31859cbcfea534e626a254de33956d5d719334bb32e7cf37cf199a21f079a5b90497228994d05efe19ccd8c769cd81f896286e8ae557cacd1630a928c629ecdfece29ab3697794aa707734e007318fa7029b050bb09ebbe6986187c6ca843f55266d275620b3f0fec0ad5f847ce8b314d929d128b33a249e", + .A = "9d5e345793faddca9867f23eeddf6816c1e837f7a2cf96fa077212514acb6be87ac01a237d8f2f1d07d27a8ddd1b0ae0d97e1bda4f205a89435017284cdedea3e407b1b940d6f52112b6359b3e86e4c83074b17c210ae2c8856b42b169b4a7a6dfa65b368a7959496cf9bb1ee93d019dbd79101830e3f5ed08604ab90890b914", + .E = "95793fe33696f53e37498b2b65aaf27079e27acf1da97dda2c3e0803e8a02139f574e04ee03f7d1ddd029f528e3f3644515ad6f10f0beac2767f23d9cd8a8b9b6c6e376e36b64a0ae2711d7d31a5a75011641935b503110edbefe9f0ff2da27b5c5f6bb8cc151fdc86f67191bb99160c6cacc86ca368d5bdfafd3f3ff5161b1e", + .M = "8315dacf124bd473c578946347e83d1b20c750a7d9533d6215591be40bc78bcca77821f8c8f95375bbd6372515ada63d22bed2fa49bd6fabb0040c538d08db25b09d2fda02a93ab086cd1c27df93c37ee9c6a0527d089179b8f92b5dc3acf5ef1c75906fb80b03f5c2442a7a4088640f66376575ecfa4c697c1a571397ee5a0d" + }, + { + .ModExp = "01", + .A = "e6a079bdf7b0638d50b183475e9ddfd5cbdebfb29f5fae8e9be402a0bd36085737b556492ea7fb4b1000ae9ce59db66098129b757cfb29224275fdaa46b8b7eb18a93ca7d3e446dc38c734b683d7ba7927b008d993aab01f44239d3c76be76d1503908e9b5e73b36c43ae0771368b01f39c042693bd92c4fc50810f059e1b332", + .E = "00", + .M = "81dd561d5d5327fc5ed7c9236b5fb21ef713c6d5e36264ba65ccc801b8eb107b714aad65bb503bb1f4721c0a6f97e5ab89300f049f42a4616ae43d29c089c286687484d18629c1be1b5befbdd0b3cfc86b1d28add89df4cc5e68dac3f56f2490a9068ca9c634ec258c030ec5023baa9133fd2af32fd1112895f9da549d410247" + }, + { + .ModExp = "00", + .A = "00", + .E = "f0460c5ca9b3a5c2d1b93c201d020dc43e1c81d1daba432e2cd310902da23eb81a5172b0b357484eb8fa2c04c270893b8198c8ad35453405dadaf05195b3aeb5ec0ccacecb4b6227ca43b27b97e240a4148a472670ed60f304302f757495fd4a91af0fe09800db0c3043a6ae213bee6703ad80523ca433d99ca0eab1e0b7c929", + .M = "81dd561d5d5327fc5ed7c9236b5fb21ef713c6d5e36264ba65ccc801b8eb107b714aad65bb503bb1f4721c0a6f97e5ab89300f049f42a4616ae43d29c089c286687484d18629c1be1b5befbdd0b3cfc86b1d28add89df4cc5e68dac3f56f2490a9068ca9c634ec258c030ec5023baa9133fd2af32fd1112895f9da549d410247" + }, + { + .ModExp = "60719701a2dc0bcde281a93ce0b8421d1a718adee43c1b5d9fe9e697a48ab3db4f9f33c73cff305ab6b6c300c149b05c6b289dce4580860dc56bc59de81ac074ecebdc65aa3ca040b44e5b3c80ddba1658d78b9abbc4c77e5f171f5582e70ab4438a8e1e2f062d618c4ad09c70c73b5b5fbc9f8f0bbdf1d530a933b705f85af8", + .A = "e1b400cd3b1f2f1c6b437adfdb970d2c8108f1b39bdbb13582179552011c6c97cba6bff2c463212b7f62776aa3e3aff9f175990e79395e819c144350b0a23d61638d500ecc97726b098e1af334aece23a851c718612442c04eb7b3805a24cc8f5b90042145eb5e5d6a408092832b6bbeb8a621419a9282fb5c075f41c7f1fdc1", + .E = "f0460c5ca9b3a5c2d1b93c201d020dc43e1c81d1daba432e2cd310902da23eb81a5172b0b357484eb8fa2c04c270893b8198c8ad35453405dadaf05195b3aeb5ec0ccacecb4b6227ca43b27b97e240a4148a472670ed60f304302f757495fd4a91af0fe09800db0c3043a6ae213bee6703ad80523ca433d99ca0eab1e0b7c929", + .M = "81dd561d5d5327fc5ed7c9236b5fb21ef713c6d5e36264ba65ccc801b8eb107b714aad65bb503bb1f4721c0a6f97e5ab89300f049f42a4616ae43d29c089c286687484d18629c1be1b5befbdd0b3cfc86b1d28add89df4cc5e68dac3f56f2490a9068ca9c634ec258c030ec5023baa9133fd2af32fd1112895f9da549d410247" + }, + { + .ModExp = "01", + .A = "9dd1e6f2d3ff24096b54e0ebf0f10e283e484a1cbafc0431adda1296ed97692f3ba99440fd4f67c96dd8bab850e1123361c99362df9ea205ff8e90d1b329459f54730992d5a360e46fcc5f5a909e691abb9a06613d6991bd7c2aa609f0d7b441d7ded0c07b8c394327672d38a905efb2d76aa3be5bb14d0c002aa37e287aee79", + .E = "00", + .M = "fda6f9d8588e3614f5a68ce867a5619f6ddbb8d64450ff402e1c4f1a08b518f79dca21e5983c207c5b7324c16895a1e9f1282fc6cf60b0645f6b02b652ed5b129e67c939e854ab492dec30ea878c3edde10a4b7d1d14c57100c6cbcc5fc085a0d7308715ed132fb917251919c727487fedb66500d5610b0014a43419acfbb92f" + }, + { + .ModExp = "00", + .A = "00", + .E = "8622c37631e428402343dccf8ed09d47b3f4201e95058910289a62707c3ce0b7113c390056cc4796cc9893e471b12cb3f63f900f3356ffd25c8b2fed6f6a7fba2c684eb241ca706c76cecbf72473d8a58c02338e40714b5610465cc319f0a529a7aa3898d9e638b247abd1380c6e8f7fa210c9f1a1a2164db6db83a6bba79436", + .M = "fda6f9d8588e3614f5a68ce867a5619f6ddbb8d64450ff402e1c4f1a08b518f79dca21e5983c207c5b7324c16895a1e9f1282fc6cf60b0645f6b02b652ed5b129e67c939e854ab492dec30ea878c3edde10a4b7d1d14c57100c6cbcc5fc085a0d7308715ed132fb917251919c727487fedb66500d5610b0014a43419acfbb92f" + }, + { + .ModExp = "86fb0b8dc161c41de2adb0f3ddcc8ad49c1efd729a52793a3ac987d4011c9c1dadb18657dca718df75c8ddcc49d60f152c46ab85ae9076ee7bfd405679a7da3a5195a1bbfd7d2b998c7b135ea91f8c445cbafe1276fa502c2a85477716829a2e0d24ba02623405a3654bed8f355bc7ccdb67c3f9a01e249e358b60d7699498a9", + .A = "816610e6018ca47074d55750dd16a281019dbf95dc752605794cbb8ea8d75775317ce685737859728320b529fb3b4414b40bf3a93d08d8994a21ae54682cc1c357eb529837a7b0129a0843eebd9341c9bee3a8ae30475bdbff517e885a0c9f2b6a680643bd981efb53bf9dd49f3dc3cb757e117895fb34b1b4336d9bf8384558", + .E = "8622c37631e428402343dccf8ed09d47b3f4201e95058910289a62707c3ce0b7113c390056cc4796cc9893e471b12cb3f63f900f3356ffd25c8b2fed6f6a7fba2c684eb241ca706c76cecbf72473d8a58c02338e40714b5610465cc319f0a529a7aa3898d9e638b247abd1380c6e8f7fa210c9f1a1a2164db6db83a6bba79436", + .M = "fda6f9d8588e3614f5a68ce867a5619f6ddbb8d64450ff402e1c4f1a08b518f79dca21e5983c207c5b7324c16895a1e9f1282fc6cf60b0645f6b02b652ed5b129e67c939e854ab492dec30ea878c3edde10a4b7d1d14c57100c6cbcc5fc085a0d7308715ed132fb917251919c727487fedb66500d5610b0014a43419acfbb92f" + }, + { + .ModExp = "01", + .A = "9edfce4691f46eadaa2043c7b1092b831ed50f3429f0bca02f985c0b77c686d951be84d772ae4b55f08935bed6e3206c8441574f215736b5c1c1b7595b3b789b55cf56db83741b10144d6767ba2b97b23a5e83504c60e06ab22834b0145655aa0463108317a379cbfc8a93de8a66925a999b8b02bf88dd85fb9898cefe9c95c8", + .E = "00", + .M = "dcb68f6aa530ae9b31d078e2e82670adcc98228e7cf1aa59f81e66426ef14b1591b833d889463564c75b5fd5551ea295a0da581dd80f62c7008ff0f26a1c9f4f756431d48198af157149be8698336b306b0a8b8635d3fc2c4c2194ecc4d2af31ca1892917cc2e621d702eaaeed0d9a0c3dca575451eb8bc5487e313988cae745" + }, + { + .ModExp = "00", + .A = "00", + .E = "a3be10ef04535fca6784e5dbf3733d677dedd50fabbc3a860496628950b4747a328c2ce0d903cbe1e700f0af30f59fb917202257815097a2b516df5d0a82642faeffdfc3b7883766c78fc4be5901ebef891a9ca27f3bcf00960729e659bb3fddd54a19ce628e95ab86e4c7a168588bc9f67b05dd21a583acd8dc36e615945648", + .M = "dcb68f6aa530ae9b31d078e2e82670adcc98228e7cf1aa59f81e66426ef14b1591b833d889463564c75b5fd5551ea295a0da581dd80f62c7008ff0f26a1c9f4f756431d48198af157149be8698336b306b0a8b8635d3fc2c4c2194ecc4d2af31ca1892917cc2e621d702eaaeed0d9a0c3dca575451eb8bc5487e313988cae745" + }, + { + .ModExp = "442866609915aa6f1bae9dfb59e721e1b63f42c0f75fbf0a88344120fbbd7aacf15208fb7c9d8bb8477d553cbd826d7e685ad764a8423e81c2131c040ee83a03cab8d5ce50866a941b48c78e9f1330794d908562d4141cfbf26e8c80c69551339eec41e37e2b37b54330f7bd75748f8d26d56ab9eb3b0c127540484c6445a7fa", + .A = "8ff65e2cbcbcd8697cc3ce9a26855d6422ac7eb4e66500648c08be697e005cc3c854a54cfab91d43489cd60be8b516a9b3c9688e5e009a1689c6b164a133859a5464ef422c86344fef42cc477c9df27768377c126a066d1b62f593b7f6d6e906feaee16addb7cfbfc043d741b7dc81a87c17f167b7b8ef1b1fb3dfd1eb14102d", + .E = "a3be10ef04535fca6784e5dbf3733d677dedd50fabbc3a860496628950b4747a328c2ce0d903cbe1e700f0af30f59fb917202257815097a2b516df5d0a82642faeffdfc3b7883766c78fc4be5901ebef891a9ca27f3bcf00960729e659bb3fddd54a19ce628e95ab86e4c7a168588bc9f67b05dd21a583acd8dc36e615945648", + .M = "dcb68f6aa530ae9b31d078e2e82670adcc98228e7cf1aa59f81e66426ef14b1591b833d889463564c75b5fd5551ea295a0da581dd80f62c7008ff0f26a1c9f4f756431d48198af157149be8698336b306b0a8b8635d3fc2c4c2194ecc4d2af31ca1892917cc2e621d702eaaeed0d9a0c3dca575451eb8bc5487e313988cae745" + }, + { + .ModExp = "01", + .A = "fe9f77f7d0475e00ec964c0effb9b8e079c32e376ce77a9c40ce4018c3df44a77b4f294d9565502b2b79accb30cb58dda6d15e1543b6d4a53296543ed11c7f51baab60283ef03fae37dfeacb431392487ec2839551a933895c4dbf18844f7b375d3e6f558d3c39993cea1bbf7fb743a6a07bd3753c03eb7298811476d7f3ff1d", + .E = "00", + .M = "e7a96cf6fa930f73c8bdc2726bbba246001a9d27f39cc2b978c99dc6f15af0e8aaf26b565302f1112e607e2df4066948baba931b89cd9bbdea2072e05b9a4968fdf282c43d997987c3a3a0434e925a679ac81f316b7a7b724b79be3d6888b66f4512759bf66cfaaa88b9513dd27a44aaea75437268a014c4eb50ba2e50093511" + }, + { + .ModExp = "00", + .A = "00", + .E = "a0bc148ed50a9b54036bb8fa1f214979052ebd47db8b347af3bb03b806bb457b468ba34781f8a25f289a7a90af4903dc14809a166df2f4c3527de2ea6911cb1afb9071a4afbb522a7d50634d66fd584c73f32d05217dc9f7f16394c68a692a953492ca85f89cc11da95fd8cac6231647923ced48a1b3b0ee68c010286d452836", + .M = "e7a96cf6fa930f73c8bdc2726bbba246001a9d27f39cc2b978c99dc6f15af0e8aaf26b565302f1112e607e2df4066948baba931b89cd9bbdea2072e05b9a4968fdf282c43d997987c3a3a0434e925a679ac81f316b7a7b724b79be3d6888b66f4512759bf66cfaaa88b9513dd27a44aaea75437268a014c4eb50ba2e50093511" + }, + { + .ModExp = "91fd879d02f95a9f40fcd1037726f73892caf84e9b43b4aa4126d9062a0d22c464e7af2fbd91aa849612d99d9519b724a7fb1cb018fffdcff321d883ab2519953c9f174f09dd8f13ac87339887385966eb4a94842276637b2c36c0a5036b1d3bbea438bc6efd4b4851c7ec06879d60694df894717569bcd31c4b13d80df6cbca", + .A = "cdec5edc1cb3ea974342b85aabc0f9385cf877ca328747d40dd4d297623ad69ab6582653faeed5aef225208305135cfbee32e066cb43e18afacea3a32acc8aabbc49617ac33e741651924ae56dd6aa044a12a1ea50fef573b5befb2f4b21b9cf83ab2aaa6fd153580a0761666ade8fb94f202a3c3dc4f33297eabb4564374168", + .E = "a0bc148ed50a9b54036bb8fa1f214979052ebd47db8b347af3bb03b806bb457b468ba34781f8a25f289a7a90af4903dc14809a166df2f4c3527de2ea6911cb1afb9071a4afbb522a7d50634d66fd584c73f32d05217dc9f7f16394c68a692a953492ca85f89cc11da95fd8cac6231647923ced48a1b3b0ee68c010286d452836", + .M = "e7a96cf6fa930f73c8bdc2726bbba246001a9d27f39cc2b978c99dc6f15af0e8aaf26b565302f1112e607e2df4066948baba931b89cd9bbdea2072e05b9a4968fdf282c43d997987c3a3a0434e925a679ac81f316b7a7b724b79be3d6888b66f4512759bf66cfaaa88b9513dd27a44aaea75437268a014c4eb50ba2e50093511" + }, + // Craft inputs whose Montgomery representation is 1, i.e., shorter than M, in order to test the const time precomputation scattering/gathering. + { + .ModExp = "9442d2eca2905ad796383947b14ddfcc341f5be8fec079135c36f6f0d9b8b2212f43e08bf29c46167ff0fe16b247cd365df4417d96cc31c94db1cf44b73b0ee3ebcc4920d9b0d003b68e49c1df91e61bc7758a8a1d2d6192ff4e1590b1a792f8be3a1b83db3ad9667d14398d873faf5d885ec3a2bef955026fae6dbf64daea2b", + .A = "3a4b4c57e62c5e9d1a9065191f8268fed9d5f6f424d071acef66f0662b8210f4c029ed991512e40c9c912043c816d2c4c5b53fa0e5c253e16808aad4225130dafbbb89fd4f30cdfc1c2f2179b636a7ddc4be579795820b4b9377637bd8a21a0ef5a90d0e0f865321eee23d9be2a3b7320b4012d02941b892df2c40bdc85c1898", + .E = "a2c56ea1362511cac0301918e15a9afe7d37edd438a5c3538d258ea01f0a6df758de07111e868b3ad8fc89b629b4955d78a1b3af902be1806410ddde25ccc6a196ba5949395c1ad5d8725b18815dc1cd5ac1c7dd17773f571e3f2e628255af14476e0494be23a4a4dfd18e23142f33d7a59c236fec61660e360d9676a747c69f", + .M = "ede35a3a7afac817d413373a2032abbc067b1493f709ae6e1282ee5469743391d891b904938857168802b7872d3cd7ac18ab249a9e540a86f970b1d0f310a4cc29df1cc9d4063d98c554f1a32f4ca5eba3523cdfb142e0fc609907c7a92bb0187009d97ec471db3545f42dd5fd29c07b7816085d09477ba31fcf90084660116d" + }, + { + .ModExp = "a7f5844fa9e7202d4b70ee252c9846e63d3d091b0387768ded872cec53458e19df0d9b4960226e269b8ca5dd4c4eda423a67b6dbb48235c08c12c6c7c78db47287756d3ed9cecb9232f7d18d5d80b9676cb68ba4a290c97e220beb1a069976b5e6022a4c1e5ddbeec86b62dda24ffea1deda37695c9f61a8817218e6370c0679", + .A = "7d6d0cc947ceb949cdc4e9e1044f5deca5bb05a491041e0d85bc4b92a0944a57c72845fad91e59010c61ad1712bd2f612d53a846a044632262a9f2e3373b062fde2484e0c165ff947f2469f743ab6e2e5e13c640fc4029b1c9213eb8473c674e7f9e95a4a5c5636d4656c1e696962340d77b322daba47d6fc894f2a2cd9e0afc", + .E = "b78012afe806e2344d004c739c97324256850980ac97d88c4ed9a838517639ca112e235978d21a176c33f5a68703aba0f2a05501bbe3fc8d49a000fbf530cdb431581dfaf8683cb15a2aee5e239cbc542827100da3b47babf4a16ca7c588aff9912e674abb449e0b767a15e415f4e7f2bbd6380d7131da3df8d49b13bfd35ce3", + .M = "b72d5c55bd2998472f1965e75a51be6155c1ba04656da8f66bcb34db36a7b1db66a89d1d05b1bde10206acf85be7b474ab689220faf1bb52ab39d8dc00512dd4e26df1179c11b973e1274db85a88c7cc2a17113abdffe58cb930ddc5f3ccc4d68b4e65c913730509f7ce5656e8bbaba9b1be177ab9f766678f018fea05da9cdf" + }, + { + .ModExp = "465ff295786a88496828fdc763e9292d557957544e9322b7996807b87fdbfa7a11614bffeec557ca831c4824c8e4ca3b1a1c7f3f4f95ec3fd6a86b73bb13d78b73af2b3c7e76954d0cc03bcb0cd606867ebb3765a8b3d0108cbe4f343a14016be9c33f6d200f0dc547e7d6b02bfab1e79dcdf9c9835a814cc6c855a12ebeb66d", + .A = "89ad02bea3e9ab839a6e23f20122409daba52c68e1e893034b30d321c0305434a6af940015e3fa5ca9c35230da34beeb1ed4fbce6c1da3a8bfe3f3ae172276c1d1723b47ee61e6f8fcfdafad102d6f7ee2a79f510c7edb93096205a40a6c9e665b88b18f39a979e2e61286d939952a6f02fe8148b7515bb25f4252337cb6e60d", + .E = "cbd6ac628cc7afa3c61bee9c22a06a395087ec1811fe9681b55216700c435996c815e7cec8aaa90016dd2382d0306a5414630124e14f3d396a4ba02ee17851bf720f1607ff813e4bbddf01338983db12f59bd6371a738eee3eeb716f21051d6174d2d6c77602942b9edaac18d4b3a723096c0d00dd23a8a605c585022f311560", + .M = "fa7a3e40364c8a8d0f14f0213a3f3e035222ca0ea19d46d10ba41580e5dd2805c8a133f3856d7d5d97f922ea540e5eb0d10ad04dfdbb74f518f58da0099a6fc2b3f3def92985176e07fc78aff2faebccca10a429794e5f15ff92f75fe90f527c60ddea8093a9078c703c372ca09f7aeb27ade02f3595308c61dd9c44e62fd101" + }, + { + .ModExp = "cf08bf00261402102e9fe03f3074471dcf0e9b3c96d4d1503f099f24ec85e1901b023e9e048c1ad042244f5f70b38b25a99f4c0a7b57d5844bb0d0137367f45f4ce2cc7746105b77414768cb97648dc5721149aed2d4c682408cc0d50d26dd0bd77e848911f8625c727cac5f32e63bcb548f41a57d718d772f23983a42f603bd", + .A = "a419646a6631c2c69b18f7aa65011825eb31692eecaee9d74f92d92203811b68e9764bda31a1585bdf69b6273fc6f9f508c395ac081336506525dad88473512f08a205621ac8b16e9864c7a7c5a4f17435de00d0b32badec6ce4897e3e1076c562b6d9523f63d0b2079eaa416cb090471657763f24931d955d1fa2720c80a9c9", + .E = "d5a6f4a1842aaee39805356dc8d0d678ee03b2c81277345beccb2742f899132feb43271f95968a01ae68aa8277201851992dc0aa7a71c90aae71b124d873ee264ea400fb131be0fc6c4ce8c04c45f6bdaca89ac743635caf6158983d257e21cef6800d7f990e912ba21bbfb8fb779afa4abd19e07e7e07eee9908493d1ca502c", + .M = "e739689b6cc6def1d45fb1a2ab551643beeb303f4aaa4da47ee5e4948510f8445b4c40e99ae8354dede60b2ba6694e93bc4d573b7e8adf871b7a9a9636eb7d70f2e49328e2d7978143b177cee8374ef01bd1ee2d95862765883f5e7971668b53ef0ff41b6539faf63c397522b0bdce916388e72e26c8d3d2e58dadeb9eb5d479" + }, + { + .ModExp = "827e6312ec3b14600203bb83f5b277ded197b2967363630ef673240df05edd3ba8ab2b11c86251a612206569c6c33952b31e264f129909bfe723bd0ee1624b36cfcfaa893a6ec8b5a1f7de79f83e79b459a3350f89f412ad1cfd6bc4c2a7a29272c783d6ecceeb1398fa17041835643f4debef9b5e87b098d104bb8912dddf7c", + .A = "b8e49c637829021d32db3a39a0c1e58cdd4c6e4eda7e8e9293be379e9c2e2d184f929d278598a81ae231cfedcf69cce4a6e31cda3c8ac14d753a7311f2436e29795f0dfb60259a0f61a997918ff984aa2284b43a9d64c974059e9682adfffd018305835f74eda8c75fe4877d811c1620f654ec9f7f32d1af5ce59115e2f41785", + .E = "80e0febf369d234bf1aaad4f82df2e2ff02882c3184781f6ccdf4f7cd93b6887af86830077c84dfb02109ada05b40970b1c65228b0c19030bd6361c3537fee22a8155c03b4e7007ca006c6daa3659518d05bb81ea0079456d0ef6116df248dffdb0c935f321f5a1034deefd5a9414a0652aa6548de33325b474b9e5a8507a082", + .M = "d5eb1d14af842a9973274f7463d90cf0ccff19c47d710edbae184478d4f29b02693ed7958bd487054327b9e6d8879e24c9af7730b92f323eeac05558da6c1b952e5dbf13de236050a77628bb5325fe0d14cc5773bf73338759d5ab43c212b414581280f1cee250007e53791b800b61c90de0328acd7bc43fbdda48158939392d" + }, + { + .ModExp = "4a1efd29c7e78549f5cd4deed1454b37462c7810ee6a8a2493b764dfa479be13b314cf9ff98259517d61865567ef499a511630c0038c97914625df181c6fe07892f329f98b344a78d751e9471483eebaa7977371bf97bb25187ae7e93a9227d6c124ccb4644423c961a11ae59c4354f89d5a95164c23d9aa256e289e9cc0858e", + .A = "bd86c9211fa6a47a06e5016c46cb8a99e34a043a29e22f8c3196fa7197c26b38927b8d9bc0ddc11a5fa4bcc44deb69dbf37cbe7ebc9a2fad6c74e09ab5a9dd929fa04ab4319b6caad1035739be78ba631fb0748d9e53944836d37ccda6e6a62823c696d8f31139ccd7f2f86b22fa026ecf433cfb1271a3539ac4f1c83aaac059", + .E = "c40b9972006d28a84c2769a86e526a2b274f73afc7c5c6a2742166757f61b5f5fdbb228afa157af62af989ffe966f232bba9e6beef5403d1690ade31a6410f7f349a35bc4267a129afd647993df7d45cc0e1a1ba4678d7f1b6e8a344d8ff7037679e1f4db25a454e4246f6b55c416567fcfa188e8a3865115851d9edf0aa8902", + .M = "cf424d7af75ce7eef90cad75ae55ca8810cc7b4703fdb5bce701e7bac07e0c371cae06df2aa8facb55a0faa6793e4d2bd9d7969703743b9be170be82792aeea55e2bc0f7ab7617b276486bf474dee2f4556aab595ff3ef115139cfe5e21ccd4ee05c0e1cf901bd85df86cc17195a783b0be836d00bee82ce064077f9191188f9" + }, + { + .ModExp = "3137a3049fd4ad2e26d870f5c998cf11bfe82101884a82e85e43facd0928cd7434a2e346ca124619769fa141bbe92ad6f36b99231032ddaec3b349a410f82b5ca36f45e56e5fb85dc63d32053dc90805d3f1854ab385281a71a57726bf97158494e7476057214ca7379ab8b70f5bdc15f70bdad3adf33c3a1f9cd1b6bbbad556", + .A = "039a1dc6a4c3f14d9c350ee968d5ce139ef725952c967a2d1bedf48ace22091283525be03807e2e263d2640be77f0525247bcd07149bba50568cec5a082c87d72962cf9e43bcb5cdb1e7e9a650fb53e0ec2fad37f09a9f036c0d7dfa528fef846769f80a9a60854910ca1b4ee05dba82ed2ee018348d6b3e52a764b8ffae61e0", + .E = "deaee3a3f80c9f684ed7110c0653847ccc7be5ff6d982fd4b49f59b5dd35f7210b1077babbcedbc127df35cd469dc6e569a0f84e58149b5605c94b09fd7f0b098d02b4a04631328b3fae39e6c2fce25334225cab71829abdb9507cb903701559660f2c08c3b743336119d1260a0db27054cad3f28bc1b04b2289baa58fb33965", + .M = "938388927d06ed3bb1286c0f06d3054cb0ee16dc7a0bbbf13a45293c09a5f40f1d611b2e1a1b0ec2ef109b508e27af4274954905cae52034f8740a744153b4d22059f0dd262ea51785522098ecacced6da07709ee6b5acc8c4e99331379a7c3de7f4e2d1431e43b19570140955b7bcba118dfbaa552cbfa2be531e8f781166ed" + }, + { + .ModExp = "c15ae334455d9f4d1030cd33e734726a27c63624c2afc576238cce5e0498298a4a0c93090a0d19568b41290303c4b558f3d9dd74f9cde8798710f68569ea0d6fd971ce67ec5b54495031de3d8842b8b49288725bee5c9f72b99054d64986ccd4e18d70d5f33943f08cd694eff538f84438ea993ebaba0910c95b3a694f213510", + .A = "def633b955a917569df3ba8517455eef0655e7a35985edda27097a063e0d82c7c3a76dc36c5d8a71ba9d540790ddd0ea514aaed98925f9a1808eb288d387aaf9605a9ef8a333ebee7ad7057bca012efd619d5867f02266f65976ef4b16da17468426ac4f99b3e8921707e01b4de20f6f9a068e6a19d872079a27f3a44449db83", + .E = "a465c47b0d15d48e01bb8b1d8e3b3253e11515f6874dbed6c25818adf1a8fd927124d5593beb367f685c11e46f18415be73ccdf16fa2e93a600b728163d21d232849e5278c3749d903edad3f1c4535a2f55a2ab65e7ebc64888bd2a0527e876ecf38cec3ab1980d08138709fad8eb88ae65d960adc3f0f8e92f784fe96fcb693", + .M = "e43cb9ac1446154356cdc31ec771c79b0e461e22d95185bbe1a279c0945e3af07903a0cb54d553380716fcdcafb4b7cf5dc6da481dc74a8c583d75ff6c1f8e429182d200246ebc473bb56e173787987c1b7fb2dd23f5b2e438a97bc4a1df628bc044fdd1e80c0cf37030adb7b04784dab827d0dcd64f0dbf37c980612570ce11" + }, + { + .ModExp = "75c3f79ab7c991b98e65505342a8a563cfb08b5d3ccf8664c7db1de50256b1d17ebf7096dc98c7bb5d7f027a894ae5cbb14dee04d5d445e775ad7e239acc82673b0ac2d819a69c83864f34e73d9a636f05de8279619a067b4c90ad038db5910447e03841d2034635018f08cbcd21efa00994247763a249082594128112f95232", + .A = "34def7d76f6f158a359fd12759fb889cdf6af0a24830dc3e84283a1ab4e9b2647a6a36b86482f829b2cdf3e3d6028f9a884b1f64f7262315446bea8b0231828e2f3d990fb103c17f820b39e4b8427c85643ceeca8f5dc8f191d1255768300e859bd7d88c770319ef38269660d221cb3bc061389b6fc0783485ef042b1c7d6fef", + .E = "c6c46453dd5aac6b37277a446b1d0c69cbe476eeff55b3ac35edb89ba97116b0e7783660f2c7b31b2a2d6c4709d0ab45d01a838100694b0777c9c9c14c959b07c437c73a5eabb7402f1001e802d797a2e7707285834fb6440a1c2f727f7bb84ddb2a49312d32fa0ce620c43872655cb5c394749c9e75d7fa25be00efe50d47d6", + .M = "fbbab6698a9142095c46b38a732592e4366c1838b84bf40f8c8fc7b630f73380a0d09765562365798f8c8030ed1b6728329d8bb06e882c35a1d59bfe84146a9db2afe42a414014e247390281c782fce806d62adb54778d2bcb49555459429d6ed446af5359657667f6aa19e8e3e0e24ab2bc312b2d90b5cb1ce6f2f15af15d9d" + }, + { + .ModExp = "ba16d7f3f6e162ce248490d164a13c00e7720d8a667e2d3ebeb13f1663e15ef5408d5b56cbc7bc793a8ca787cc50f8e15e0e9d4ee764531d04a9114eea556bb3e206ed7d85267151a056b6e68fbf35e03f2cf829708ffe1de13e95ecfe365aff1eea36340ffcd3892dee659fb1ecbe50f5080e54737c10f9c1ba638b14ef537e", + .A = "9025e6183706105e948b1b0edf922f9011b9e11887d70adb00b26f272b9e76a38f3099084d9cccf12d04b1a99c0f654f8b9ed90c6dff9478c60bf05d58d734ab60eaefa14a22230ec60c90dc1f0704b61eef0bef345785ae0e6a9af7db069cf6bd2b4e0fe58a0ade83c7e46a04b9fe1d24cb9b65c6f80de713e61d70eae5b286", + .E = "d7e6df5d755284929b986cd9b61c9c2c8843f24c711fbdbae1a468edcae159400943725570726cdc92b3ea94f9f206729516fdda83e31d815b0c7720e7598a91d992273e3bd8ac413b441d8f1dfe5aa7c3bf3ef573adc38292676217467731e6cf440a59611b8110af88d3e62f60209b513b01fbb69a097458ad02096b5e38f0", + .M = "e4e784aa1fa88625a43ba0185a153a929663920be7fe674a4d33c943d3b898cff051482e7050a070cede53be5e89f31515772c7aea637576f99f82708f89d9e244f6ad3a24a02cbe5c0ff7bcf2dad5491f53db7c3f2698a7c41b44f086652f17bb05fe4c5c0a92433c34086b49d7e1825b28bab6c5a9bd0bc95b53d659afa0d7" + }, + // See https://github.com/openssl/openssl/commit/e9e726506cd2a3fd9c0f12daf8cc1fe934c7dddb OpenSSL's test vectors do not include the expected value, so ModExp was computed with Python 3 + { + .ModExp = "ccb051a34f9e26e381e50445632cbbd4abe56bc912020f3edd2db144aedb470095c4c33e3342d1dc4bb4056ba3078366af4cee507e85bb1b2e499ef25a933810f14faa8b1a9ce5e8d58f2789e27c887a4ff87fa59ff682727a3912a99aae6db8b3b8947d76c8454cffc6fb3f2422dca106c3845b0db68a06e5e9d7b90e552506579d812e7d96bfc6324feec90ea0800463346148f120e7caf403788539f5d87ee45aa5b313c340e0a323029f3a0bdb675510aefec171c01e2a94960cd507e461214028c86ed4e9fce31e7dbdf1a75fd6f973e2aed4a039e53a60a7aa62be8ee1f80a113833ab402d07e17151021cec29fa5b2e628ef9f2d7aa4bc86b6eec8faf", + .A = "95564994a96c45954227b845a1e99cb939d5a1da99ee91acc962396ae999a9ee38603790448f2f7694c242a875f0cad0aae658eba085f312d2febbbd128dd2b58f7d1149f03724215d704344d0d62c587ae3c5939cba4b9b5f3dc5e8e911ef9a5ce1a5a749a4989d0d8368f6e1f8cdf3a362a6c97fb02047ff152b480a4ad9852d45efdf0770542992afca6a0590d52930434bba96017afbc9f99e112950a8b1a359473ec376f329bdae6a19f503be6d4be7393c4e43468831234e27e3838680b949390d2e416a3f9759e5349ab4c253f6f29f819a6fe4cbfd27ada34903300eda021f62839f5878a36f1bc3085375b00fd5fa3e68d316c0fdace87a97558465", + .E = "f95dc0f980fbd22e90caa5a387cc4a369f3f830d50dd321c40db8c09a7e1a241a536e096622d3280c0c1ba849c1f4a79bf490f60006d081e8cf69960189f0d312cd9e17073a3fba7881b21474a13b334116cb2f5dbf3189a6de3515d0840f053c776d3982d391b6d04d642dda5cc6d1640174c09875addb70595658f89efb439dc6fbd55f903aadd307982d3f659207f265e1ec6271b274521b7a5e28e8fd7a55df089292820477802a43cf5b6b94e999e8c9944ddebb0d0e95a60f88cb7e813ba110d20e1024774107dd02949031864923b3cb8c3f7250d6d1287b0a40db6a47bd5a469518eb65aa207ddc47d8c6e5fc8e0c105be8fc1d4b57b2e27540471d5", + .M = "fef15d5ce4625f1bccfbba49fc8439c72bf8202af039a2259678941b60bb4a8f2987e965d58fd8cf86a856674d519763d0e1211cc9f8596971050d56d9b35db3785866cfbca17cfdbed6060be3629d894f924a89fdc1efc624f80d41a22f19009503fcc3824ef62ccb9208430c26f2d8ceb2c63488ec4c07437aa4c96c43dd8b9289ed00a712ff66ee195dc71f5e4ead02172b63c543d69baf495f5fd63ba7bcc633bd309c016e37736da92129d0b053d4ab28d21ad7d8b6fab2a8bbdc8ee647d2fbcf2cf426cf892e6f5639e0252993965dfb73ccd277407014ea784aaa280cb7b03972bc8b0baa72360bdb44b82415b86b2f260f877791cd33ba8f2d65229b" + }, + // The following inputs trigger an edge case between Montgomery reduction and the "almost" reduction variant from https://eprint.iacr.org/2011/239 + { + .ModExp = "00", + .A = "19c7bc9b97c6083cd7b8d1cd001452c9b67983247169c6532047eb7fc8933014dbf69fee7a358769f1429802c8ea89d4f9ca6ba6f368fbdb1fa5717b4a00", + .E = "bbc7e09147408571050e8d0c634682c5863b7e8a573626648902cff12e590c74f5a23ecce39732266bc15b8afbd6c48a48c83fbdc33947515cc0b6e4fb98ae2cd730e58f951fec8be7e2e3c74f4506c7fd7e29bdb28675fe8a59789ab1148e931a2ebd2d36f78bc241682a3d8083d8ff538858cd240c5a693936e5a391dc9d77118062a3f868c058440a4192267faaaba91112f45eee5842060febbf9353a6d3e7f7996573209136a5506062ea23d74067f08c613f3ff74bade25f8c3368e6dba84eae672eac11be1137fc514924fcab8c82e46d092bd047dcbadaa48c67a096ec1a04f392a8511e6acbad9954949b703e71ff837337b594055ae6f3c0fc154447a687c9ac8a2cdfd64a2e680c6ff21254735af7f5eb6b43f0bce86bda55a04143a991711081435ed4f4a89b23fc3a588022b7a8543db4bf5c8ac93603367c750ff2191f59a716340fab49bb7544759c8d846465eec1438e76395f73e7b5e945f31f1b87fefa854a0d208846eaab5fa27144fd039911608bab0eaee80f1d3553dfa2d9ba95268479b97a059613660df5ad79796e0b272244aca90ccc13449ec15c206eeed7b60405a4c5cfdf5da5d136c27fa9385d810ad198dfe794ffce9955e10520efea1e2eb794e379401b9affd863b9566ce941c4726755574a1b1946acf0090bfb93f37dd55f524485bbba7fa84b53addfde01ae1de9c57fe50d4b708dd0fa45d02af398b3d05c6d17f84c11e9aacdbe0b146cad6ddbd877731e26a17f3ebed459560d12ed7a6abc2ea6fe922e69d2622ef11b6b245b9ba8f0940faaa671a4beb727be5393a94dafaeff7221b29183e7418f4c5bb95a6a586c93dbc8ce0236d9dbe26c40513611b4141fed66599adbfb20fc30e09a4815e4159f65a6708f34584a7a77b3843941cd61a6917dcc3d07a3dfb5a2cb108bacea7e782f2111b4d22ecaaeff469ecd0da371df1ac5e9bf6df6ccba2d3a9f393d597499eaca2c206bfb81c3426c5fe45bcf16e38aecd246a319a1f37041c638b75a4839517e43a6d01bee7d85eaeedbce13cd15699d3ee42c7414cfed576590e4fb6ddb6edd3e1957efaf039bfe8b9dc75869b1f93abff15cae8b234161070fa3542303c2ed35ca66083d0ac299b81182317a2a3985269602b1fa1e822fcbda48e686d80b273f06b0a702ca7f42cbbbd2fc2b3601422c8bff6302eda3c61b293049636002649b16f3c1f0be2b6599d66493a4497cd795b10a2ab8220fafad24fa90e1bfcf39ecce337e705695c7a224bf9f445a287d6aab221341659ca4be7861f6ac4c9d33dac811e6", + .M = "519b6e57781d40d897ec0c1b648d195526726b295438c9a70928ac25979563d72db91c8c42298a33b572edecdf40904c68a23337aa5341b56e92b0da5041" + }, + // To fully exercise BN_mod_exp_mont_consttime codepaths, we generate inputs at different bitwidths. rsaz-avx2.pl only runs at 1024-bit moduli, and + // x86_64-mont5.pl unrolls 8 64-bit words at a time, so we want to capture both multiples of 512- and non-multiples. Also include moduli that are not quite a full word. + // 512-bit + { + .ModExp = "00", + .A = "8000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e", + .E = "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + .M = "8f42c9e9e351ba9b32ab0cf69da43f4acf7028d19cff6e5059ea0e3fcc97c97f36a31470044737d4c0c933ac441ecb29e32c81401523afdac7de9c3fd8493c97" + }, + // 1024-bit + { + .ModExp = "00", + .A = "800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002f", + .E = "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + .M = "9da8dc26fdf4d2e49833b240ee552beb7a6e251caa91bfb5d6cafaf8ed9461877fda8f6ac299036d35806bc1ae7872e54eaac1ec6bee6d02c6621a9cf8883b3abc33c49b3e601203e0e86ef8f0562412cc689ee2670704583909ca6d7774c9f9f9f4d77d37fedef9cb51d207cb629ec02fa03b526fd6594bfa8f2da71238a0b7" + }, + // 1025-bit + { + .ModExp = "00", + .A = "010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011", + .E = "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + .M = "010223abfdda02e84e11cec8ee7fc784fa135733935f7b9054bb70f1f06d234d76dcf3beed55c7f39e955dc1fef2b65009240fd02f7a1b27a78fc2867144bf666efb929856db9f671c356c4c67a068a70fe83c52eebda03668872fd270d0794f0771d217fb6b93b12529a944f7f0496a9158757c55b8ee14f803f1d2d887e2f561" + }, + // 1088-bit + { + .ModExp = "00", + .A = "8000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003d", + .E = "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + .M = "e91f6d748773cb212a23aa348125615123b1800c9ea222c9374c757702ae4140fa333790ed8f6bf60a1d7dda65c2767cc5f33e32e333d19fbfb5a2b85795757c9ca070268763a618e9d33873d28a89bf88acd209efbb15b80cd33b92a6b3a682e1c91782fc24fb86ddff4f809219c977b54b99359094bbcc51dfe17b992ab24b74a17950ad754281" + }, + // 1472-bit + { + .ModExp = "00", + .A = "8000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001d", + .E = "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + .M = "a8770362f4bfe4fc1ab0e52705c11a9b6ba235d5a5f22197c2d68e27ed18426ede3316af706aa79bcf943dbd51459eb15ae1f9386216b3f3a847f94440a65b97659bc5ba2adb67173714ecaa886c0b926d7a64ea45576f9d2171784ce7e801724d5b0abfd93357d538ea7ad3ad89a74f4660bdb66dfb5f684dcf00402e3cdf0ab58afd867c943c8f47b80268a789456aa7c50a619dd2f9f5e3f74b5d810f0f8dadbf4ad5b917cdcb156c4c132611c8b3b035118a9e03551f" + }, + // 1536-bit + { + .ModExp = "00", + .A = "800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002", + .E = "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + .M = "878cd000778f927b2f1a4b8bac86efd282079a7ac0d25e09ffd2f72fbc282e65e233929d2457c7b1d63c56fb706cdfa04fb87e654c578c98d7cf59c2293dc5641086b68db4867105981daaf147a0ee91f6932ef064deae4142c19e58d50c0686f0eaf778be72450f89a98b4680bbc5ffab942195e44dd20616150fd1deca058068ca31ab2f861e99082588f17a2025bf5e536150142fca3187a259c791fc721430f24d7e338f8dc02e693a7e694d42775e80f7f7c03600b6ae86b4aba2b0e991" + }, + // 2048-bit + { + .ModExp = "00", + .A = "8000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000f", + .E = "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + .M = "9f40a7535c561208ecb38e17c9336d9bc8484d335901b2cd42759cf03689227f6992f10cb6b586d767fbcdf30e9d82a0eda60d2694ccd0194fa96b50b56e0cdeec1951ea9e58b07e334a7f108841a0ab28256917fecea561388807ed124a17386a7a7b501f9cbf3404247a76948d0561e48137d3f9669e36f175731796aeaf78851f7d866917f661422186a4814aa35c066b5a90b9cfc918af769a9f0bb30c12581027df64ac328a0f07dbd20adb704479f6d0f233a131828c71bab19c3c34795ea4fb68aa632c6f688e5b3b84413c9031d8dc251003a590dec0dd09bfa6109ed4570701439b6f265b84ac2170c317357b5fbe5535e2bbdd93c1aacfdaa28c85" + }, + // 3072-bit + { + .ModExp = "00", + .A = "80000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001d", + .E = "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + .M = "c23dfd244a58a668d514498a705c8f8f548311b24f0f98b023d2d33632534c2ae948d6641d41fd7a29fbbd594bfc7fdd6e8162cbb3056af3075347b6fc8876458d33a9d0ffdbcdf482de0c73d1310fd8fa8f9f92dd0dbb0e2034e98a30f6c11b482f7476c5b593f673a322b1130daa4314e9074270dce1076436f0d56cf196afcbb235a9a7b3ac85b9062e85fc0e63a12c468c787019f6805f9faab64fc6a0babc80785d88740243f11366bffb40ccbe8b2bb7a99a2c8238a6f656bb0117d7b2602aa400f4d77de5f93c673f13264ca70de949454e3e3f261993c1aa427e8ef4f507af744f71f3b4aaf3c981d44cc1bfb1eb1151168762b242b740573df698e500d99612e17dc760f7b3bf7c235e39e81ad7edbe6c07dbb8b139745bb394d61cb799bcafec5de074932b0b2d74797e779ac8d81f63a2b2e9baa229dfaa7f90f34ffade1d2ad022a3407d35eb2d7477c6ae8ad100f6e95c05b4f947c1fabfb11a17add384e6b4cd3a02fd9b43f46805c6c74e366b74aa3b766be7a5fbbd67fa81" + }, + // 4096-bit + { + .ModExp = "00", + .A = "8000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001", + .E = "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + .M = "8030411ecbddcb0fe4e76fd6b5bf542e8b015d1610cf96130ded12ba2cda0641bd9692080f218ea8b0d751845b519d95b843542ec8d2a07f1f93afe3189b69a4f35c983011c7f7928c3df458cc3eae85c36e6934a4b1bc0a67c8a521de336642c49e10a7ffa8d0af911aacc19e3900449161940f139220e099a150dcaf0ff96ffff6e726c1ac139969103cf6a828ac3adf0301506aa02787b4f570d5dde53a34acab8fec6fa94760abf16ee99954371ad65a6e899daab87b95811d069404991de9abe064ebbddf886e970f10d260c899dda940191a82d4c8bd36651363aff5493f4f59e700007dcadf37ebea7fcfd7600d16617ffea0d9ae659446d851d93c564e50e558f734c894d735fa273770703dab62844d9f01badf632f3d14a00f739c022c9be95f54e9cea46ec6da7cb11f4602e06962951c48204726b7f120ddbd0eb3566dc8d1e6f195a9196e96db33322d088b43aecffe9b4df182dd016aca0bd14f1c56cd1a18b89165c027029862b09ffd78e92ab614349c4fd67f49cb12cd33d0728930d0538bda57acef1365a73cc8fbac7d463b9e3c3bae0bb6224b080cdb8b5cd47d546d53111fdc22b7ff679bcfe27192920ee163b2be337d8cccc93b4de7d2d31934b9c0e97af291dcc1135b4a473bd37114eec3ba75c411887b57799d3188e7353f33a4d31735ebfc9fcfc044985148dd96da3876a5ab7ea7a404b411" + }, + // These are regression tests for code which historically reached the RSAZ-512 code. That has since been removed, but the test vectors remain. + // Note that the lengths of the inputs, especially the *bit* length of |M|, matter a lot. + // Control: No relationship between A and M except that A < M and they're the same number of limbs. + { + .ModExp = "7f34c1cd63377bc3abf2bb5b2d1bf5f06454e1e8040fe19a72245ce9731cbee1bf9e84532300776c8021ed4f3a8de508d85b4cf320bd82065a013754857b50c4", + .A = "8e4e67da6ff890643d0599387955996ef6f0c2045eb9944576ddb965ca64cdb6247727ce128ef178d4a84e5a56d2e67eb0fe389ecbf691f9244ae80f4c11b364", + .E = "0be99d8f0650e540b9b191e9cf96f74881b902e32ed169ffd8a1776c3f3e80f0ac765aa14615713e1549f250a20fe4ee48c4e0c6176162fc7842a0dd64d640d1", + .M = "f12f2c19ee1ecf2c999b87bdafde60eace3790faad8f9adec13b14c6dfb69f8795a1d0fe65494250b59534014b918453042012952ae6f5786342999600725491" + }, + // A == M - 1 == -1 (mod M) and the exponent is odd so A ^ E (mod M) == A. + { + .ModExp = "f12f2c19ee1ecf2c999b87bdafde60eace3790faad8f9adec13b14c6dfb69f8795a1d0fe65494250b59534014b918453042012952ae6f5786342999600725490", + .A = "f12f2c19ee1ecf2c999b87bdafde60eace3790faad8f9adec13b14c6dfb69f8795a1d0fe65494250b59534014b918453042012952ae6f5786342999600725490", + .E = "0be99d8f0650e540b9b191e9cf96f74881b902e32ed169ffd8a1776c3f3e80f0ac765aa14615713e1549f250a20fe4ee48c4e0c6176162fc7842a0dd64d640d1", + .M = "f12f2c19ee1ecf2c999b87bdafde60eace3790faad8f9adec13b14c6dfb69f8795a1d0fe65494250b59534014b918453042012952ae6f5786342999600725491" + }, + // A == M, so A == 0 (mod M) so A ^ E (mod M) == 0. Note that A mod M with a "correct top" isn't the right length for RSAZ. + { + .ModExp = "00", + .A = "f12f2c19ee1ecf2c999b87bdafde60eace3790faad8f9adec13b14c6dfb69f8795a1d0fe65494250b59534014b918453042012952ae6f5786342999600725491", + .E = "0be99d8f0650e540b9b191e9cf96f74881b902e32ed169ffd8a1776c3f3e80f0ac765aa14615713e1549f250a20fe4ee48c4e0c6176162fc7842a0dd64d640d1", + .M = "f12f2c19ee1ecf2c999b87bdafde60eace3790faad8f9adec13b14c6dfb69f8795a1d0fe65494250b59534014b918453042012952ae6f5786342999600725491" + }, + //RSAZ 1024-bit. + // Note that the lengths of the inputs, especially the *bit* length of |M|, matter a lot. + // Control: No relationship between A and M except that A < M and they're the same number of limbs. + { + .ModExp = "8984f8c16044f9c0ad7bd72347af90f58e6e003acda92b76e3c7c4a56ea8e918409d8e9b34884d4c89d0b17cb40fe898f2627c084a0f1698e46beccbf6f48eecc281e11ea9e5135adba460ddae157f2c655b5f589ce29b254d43a960a71cede8a08dbb86be4dac22458da232fb1ec2470856827302ed772c9ddafa408c931aa7", + .A = "21158da5fe20356825e72b3f5384ec57720d22f727b27ce2f945c8ee311db781add73bf8fae96b775c909bd22fca75c44c2b0584284a5bb1c07f8eefcd6b0a44047a02b185df34f897f11d4fb9a86c9eb841b4cb8d0383441fdc5af3ef385b5e8380f605d73ed41bb42eb2c2a5704d6034b3ad058dafffce83dbbfb6295daaf8", + .E = "ecdebd112b3b5788669449dcddbd479a203ee9ab72a9bb9c406b97623513bf0ab9a22f1f23634d269e16bfd6d3b64202b71fc355057411967b6ac70f8d9cef0a4e06819a9a18cc06bbe438243fa9759303d98be8a65dc1cb13595ee9b99f138554425d50f6fbc025d8ffa3eaea828d6f3b82a3584146bafde34da257995f0575", + .M = "ff3a3e023db3bba929ca4ededbace13d0d1264387b5ef62734e177eaf47a78af56b58aacc8ac5d46f5b066bafb95d93d4442bb948653613eec76837b4ffb7991cb080b6c8b403fb09bc817d026e283ee47ab2fc9af274b12f626eda2fe02004a8e27b9ed7d3b614e8955c7e7c2c0700edd079455237c4475fbd41857e206e4b7" + }, + // A == M - 1 == -1 (mod M) and the exponent is odd so A ^ E (mod M) == A. + { + .ModExp = "b5d257b2c50b050d42f0852eff5cfa2571157c500cd0bd9aa0b2ccdd89c531c9609d520eb81d928fb52b06da25dc713561aa0bd365ee56db9e62ac6787a85936990f44438363560f7af9e0c16f378e5b83f658252390d849401817624da97ec613a1b855fd901847352f434a777e4e32af0cb4033c7547fb6437d067fcd3d964", + .A = "b5d257b2c50b050d42f0852eff5cfa2571157c500cd0bd9aa0b2ccdd89c531c9609d520eb81d928fb52b06da25dc713561aa0bd365ee56db9e62ac6787a85936990f44438363560f7af9e0c16f378e5b83f658252390d849401817624da97ec613a1b855fd901847352f434a777e4e32af0cb4033c7547fb6437d067fcd3d964", + .E = "61803d4973ae68cfb2ba6770dbed70d36760fa42c01a16d1482eacf0d01adf7a917bc86ece58a73b920295c1291b90f49167ef856ecad149330e1fd49ec71392fb62d47270b53e6d4f3c8f044b80a5736753364896932abc6d872c4c5e135d1edb200597a93ceb262ff6c99079177cd10808b9ed20c8cd7352d80ac7f6963103", + .M = "b5d257b2c50b050d42f0852eff5cfa2571157c500cd0bd9aa0b2ccdd89c531c9609d520eb81d928fb52b06da25dc713561aa0bd365ee56db9e62ac6787a85936990f44438363560f7af9e0c16f378e5b83f658252390d849401817624da97ec613a1b855fd901847352f434a777e4e32af0cb4033c7547fb6437d067fcd3d965" + }, + // # A == M, so A == 0 (mod M) so A ^ E (mod M) == 0. Note that A mod M with a "correct top" isn't the right length for RSAZ. + { + .ModExp = "00", + .A = "b5d257b2c50b050d42f0852eff5cfa2571157c500cd0bd9aa0b2ccdd89c531c9609d520eb81d928fb52b06da25dc713561aa0bd365ee56db9e62ac6787a85936990f44438363560f7af9e0c16f378e5b83f658252390d849401817624da97ec613a1b855fd901847352f434a777e4e32af0cb4033c7547fb6437d067fcd3d965", + .E = "61803d4973ae68cfb2ba6770dbed70d36760fa42c01a16d1482eacf0d01adf7a917bc86ece58a73b920295c1291b90f49167ef856ecad149330e1fd49ec71392fb62d47270b53e6d4f3c8f044b80a5736753364896932abc6d872c4c5e135d1edb200597a93ceb262ff6c99079177cd10808b9ed20c8cd7352d80ac7f6963103", + .M = "b5d257b2c50b050d42f0852eff5cfa2571157c500cd0bd9aa0b2ccdd89c531c9609d520eb81d928fb52b06da25dc713561aa0bd365ee56db9e62ac6787a85936990f44438363560f7af9e0c16f378e5b83f658252390d849401817624da97ec613a1b855fd901847352f434a777e4e32af0cb4033c7547fb6437d067fcd3d965" + }, + // Regression test for CVE-2017-3738. + { + .ModExp = "d360792bd8210786607817c3dda64cc38c8d0f25569597cb1f363c7919a0c3587baff01a2283edaeb04fc288ac0ab3f279b2a89ffcb452d8bdf72422a9f9780f4aa702dc964cf033149d3a339883062cab8564aebdbfac0bf68985e522c6fe545b346044690c525ca85d3f4eb3e3c25cdf541545afc84a309e9b1d7807003461", + .A = "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff2020202020df", + .E = "2020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020FF2020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020", + .M = "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff2020202020ff" + }, + // Test vectors for CVE-2019-1551. (We do not carry the assembly file with the bug, but we use the test vectors anyway.) + // Original test vectors by OSS-Fuzz. + { + .ModExp = "9d675d188a07e9bd1b32638cc8cfd5002ef89bd1a9648f806567b87939140a67977dc8da17323b8e4c6bc53875cda8b656df8f54cc32e44fd9c21d122ea3c0d6", + .A = "dea9b3e0b44ae67b2ac9b7c2b18eeb4dab206b014981a46ac409f195eeb6896f132cf8497c87d1188008ee511054ebb426203355b7d515dce9501cb759ac1373", + .E = "0b01ae745b101e9e45ec05dcff72e7f8fc04c79ffe324301fda0b4f7be81d85c4e875c73fc6c5cb40000000000000000000000000000000000", + .M = "ffffffff01ffffffffffffffffffffffffffe2000000000000000000000000000010fab8d960706cd4c21818115650cad61d4f10da325dffffffff00ffff00ff" + }, + { + .ModExp = "651f811b62ee8770e3598c340864dd6b0be9bb6376b6f933ab216fd55538e6ad1000cb2b3c64f54d554e004b6eec8138e6ecff00452d443a42041b72e6cd9ead", + .A = "3e3e3e3e3e3e3e3e3e3e3e3e3e3e3e3e3e3e3e3e3e3e3e3e3e3e3e3e3e3e3e3e3e3e3e3e3e3e3e3e3e3e3e3e3e3e3e3e3e3e3e3e3e3e3e3e3e3e3e3e3e3e", + .E = "3e3e3e3e3e3e3e3e3e3e3e3e3e3e3e3e3e3e09003e3e3e3e3e3e3e3e3e3e3e3e3e3e010900230a01230a2100ffffff0000adf300a58700000000ffffff00", + .M = "ffffff0b00000000000000000000000000ffffffff0000ffffffff00000a0000000a00000000000000000000ffffffff000000000000ffffffffffff000000ff" + }, + // Test vectors for rsaz_512_sqr bug, with rcx/rbx=1 + // between first and second iteration + { + .ModExp = "01", + .A = "624e6a171024e6a171024e6a171024e6a171024e6a171024e6a171024e6a171024e6a171024e6a171024e6a171024e6a14ce297f2873536f959d8c3390d973b6", + .E = "8000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006e", + .M = "8000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006f" + }, + //between second and third iteration + { + .ModExp = "01", + .A = "11024e6a171024e6a171024e6a171024e6a171024e6a171024e6a171024e6a171024e6a171024e6a14ce297f2873536f959d8c3390d97360800000000000000f", + .E = "8000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006e", + .M = "8000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006f" + }, + // between third and fourth iteration + { + .ModExp = "01", + .A = "4171024e6a171024e6a171024e6a171024e6a171024e6a171024e6a171024e6a14ce297f2873536f959d8c3390d9736080000000000000000000000000000039", + .E = "8000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006e", + .M = "8000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006f" + }, + // between fourth and fifth iteration + { + .ModExp = "01", + .A = "06a171024e6a171024e6a171024e6a171024e6a171024e6a14ce297f2873536f959d8c3390d97360800000000000000000000000000000000000000000000006", + .E = "8000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006e", + .M = "8000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006f" + }, + // between fifth and sixth iteration + { + .ModExp = "01", + .A = "44e6a171024e6a171024e6a171024e6a14ce297f2873536f959d8c3390d97360800000000000000000000000000000000000000000000000000000000000003c", + .E = "8000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006e", + .M = "8000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006f" + }, + // between sixth and seventh iteration + { + .ModExp = "01", + .A = "1024e6a171024e6a14ce297f2873536f959d8c3390d973608000000000000000000000000000000000000000000000000000000000000000000000000000000e", + .E = "8000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006e", + .M = "8000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006f" + }, + // between seventh and eighth iteration + { + .ModExp = "01", + .A = "626eee5e3c8653be47ed15e84b97cc7f800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000187", + .E = "c00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002f8", + .M = "c00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002f9" + }, + // Test vectors for rsaz_512_srq bug, with rcx/rbx=2 + // between first and second iteration + { + .ModExp = "01", + .A = "3c40939a85c40939a85c40939a85c40939a85c40939a85c40939a85c40939a85c40939a85c40939a85c40939a85c4093995e8efdb195e8efd8caf477ed8caf7c", + .E = "8000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006e", + .M = "8000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006f" + }, + // between second and third iteration + { + .ModExp = "01", + .A = "485c40939a85c40939a85c40939a85c40939a85c40939a85c40939a85c40939a85c40939a85c4093995e8efdb195e8efd8caf477ed8caf47800000000000003f", + .E = "8000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006e", + .M = "8000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006f" + }, + // between third and forth iteration + { + .ModExp = "01", + .A = "59a85c40939a85c40939a85c40939a85c40939a85c40939a85c40939a85c4093995e8efdb195e8efd8caf477ed8caf478000000000000000000000000000004e", + .E = "8000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006e", + .M = "8000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006f" + }, + // between forth and fifth iteration + { + .ModExp = "01", + .A = "2939a85c40939a85c40939a85c40939a85c40939a85c4093995e8efdb195e8efd8caf477ed8caf47800000000000000000000000000000000000000000000024", + .E = "8000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006e", + .M = "8000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006f" + }, + // between fifth and sixth iteration + { + .ModExp = "01", + .A = "640939a85c40939a85c40939a85c4093995e8efdb195e8efd8caf477ed8caf478000000000000000000000000000000000000000000000000000000000000057", + .E = "8000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006e", + .M = "8000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006f" + }, + // between sixth and seventh iteration + { + .ModExp = "01", + .A = "25c40939a85c4093995e8efdb195e8efd8caf477ed8caf4780000000000000000000000000000000000000000000000000000000000000000000000000000021", + .E = "8000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006e", + .M = "8000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006f" + }, + // between seventh and eighth iteration + { + .ModExp = "01", + .A = "7b4919849931b28a14fcace213f2b3884fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff84b6e67b66ce4d9c", + .E = "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000000000004c", + .M = "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000000000004d" + } + }; + + for(const modexp_test_params& test : tests) { + const bytes base = to_bytes(test.A); + const bytes exponent = to_bytes(test.E); + const bytes modulus = to_bytes(test.M); + + bytes expected_result = to_bytes(test.ModExp); + //the host function's result is always length of modulus; pad expected result with enough 0x00s to match up + expected_result.insert(expected_result.begin(), modulus.size() - expected_result.size(), 0x00); + + BOOST_CHECK_EQUAL(std::get(fc::modexp(base, exponent, modulus)), expected_result); + } + +} FC_LOG_AND_RETHROW(); + BOOST_AUTO_TEST_CASE(modexp_benchmarking) try { std::mt19937 r(0x11223344); diff --git a/libraries/testing/tester.cpp b/libraries/testing/tester.cpp index b57103af15..6bcc9d1b8d 100644 --- a/libraries/testing/tester.cpp +++ b/libraries/testing/tester.cpp @@ -1,7 +1,6 @@ #include #include #include -#include #include #include #include diff --git a/plugins/net_plugin/net_plugin.cpp b/plugins/net_plugin/net_plugin.cpp index e8db373f81..b54ad066b0 100644 --- a/plugins/net_plugin/net_plugin.cpp +++ b/plugins/net_plugin/net_plugin.cpp @@ -241,6 +241,12 @@ namespace eosio { std::atomic sync_state{in_sync}; std::atomic sync_ordinal{0}; + // Instant finality makes it likely peers think their lib and head are + // not in sync but in reality they are only within small difference. + // To avoid unnecessary catchups, a margin of min_blocks_distance + // between lib and head must be reached before catchup starts. + const uint32_t min_blocks_distance{0}; + private: constexpr static auto stage_str( stages s ); bool set_state( stages newstate ); @@ -251,7 +257,7 @@ namespace eosio { bool verify_catchup( const connection_ptr& c, uint32_t num, const block_id_type& id ); // locks mutex public: - explicit sync_manager( uint32_t span, uint32_t sync_peer_limit ); + explicit sync_manager( uint32_t span, uint32_t sync_peer_limit, uint32_t min_blocks_distance ); static void send_handshakes(); bool syncing_from_peer() const { return sync_state == lib_catchup; } bool is_in_sync() const { return sync_state == in_sync; } @@ -1905,7 +1911,7 @@ namespace eosio { } //----------------------------------------------------------- - sync_manager::sync_manager( uint32_t span, uint32_t sync_peer_limit ) + sync_manager::sync_manager( uint32_t span, uint32_t sync_peer_limit, uint32_t min_blocks_distance ) :sync_known_lib_num( 0 ) ,sync_last_requested_num( 0 ) ,sync_next_expected_num( 1 ) @@ -1913,6 +1919,7 @@ namespace eosio { ,sync_req_span( span ) ,sync_peer_limit( sync_peer_limit ) ,sync_state(in_sync) + ,min_blocks_distance(min_blocks_distance) { } @@ -2178,7 +2185,7 @@ namespace eosio { } return; } - if (chain_info.lib_num > msg.head_num + nblk_combined_latency) { + if (chain_info.lib_num > msg.head_num + nblk_combined_latency + min_blocks_distance) { peer_ilog( c, "handshake lib ${lib}, head ${head}, head id ${id}.. sync 2, head ${h}, lib ${l}", ("lib", msg.last_irreversible_block_num)("head", msg.head_num)("id", msg.head_id.str().substr(8,16)) ("h", chain_info.head_num)("l", chain_info.lib_num) ); @@ -4033,10 +4040,6 @@ namespace eosio { peer_log_format = options.at( "peer-log-format" ).as(); - sync_master = std::make_unique( - options.at( "sync-fetch-span" ).as(), - options.at( "sync-peer-limit" ).as() ); - txn_exp_period = def_txn_expire_wait; p2p_dedup_cache_expire_time_us = fc::seconds( options.at( "p2p-dedup-cache-expire-time-sec" ).as() ); resp_expected_period = def_resp_expected_wait; @@ -4048,6 +4051,16 @@ namespace eosio { EOS_ASSERT( keepalive_interval.count() > 0, chain::plugin_config_exception, "p2p-keepalive_interval-ms must be greater than 0" ); + // To avoid unnecessary transitions between LIB <-> head catchups, + // min_blocks_distance between LIB and head must be reached. + // Set it to the number of blocks produced during half of keep alive + // interval. + const uint32_t min_blocks_distance = (keepalive_interval.count() / config::block_interval_ms) / 2; + sync_master = std::make_unique( + options.at( "sync-fetch-span" ).as(), + options.at( "sync-peer-limit" ).as(), + min_blocks_distance); + connections.init( std::chrono::milliseconds( options.at("p2p-keepalive-interval-ms").as() * 2 ), fc::milliseconds( options.at("max-cleanup-time-msec").as() ), std::chrono::seconds( options.at("connection-cleanup-period").as() ), diff --git a/plugins/producer_plugin/producer_plugin.cpp b/plugins/producer_plugin/producer_plugin.cpp index e1c13ea350..757b930303 100644 --- a/plugins/producer_plugin/producer_plugin.cpp +++ b/plugins/producer_plugin/producer_plugin.cpp @@ -618,9 +618,13 @@ class producer_plugin_impl : public std::enable_shared_from_this _ro_thread_pool; fc::microseconds _ro_write_window_time_us{200000}; fc::microseconds _ro_read_window_time_us{60000}; diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index cfae3e4226..ff05447fb5 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -134,9 +134,9 @@ add_test(NAME compute_transaction_test COMMAND tests/compute_transaction_test.py set_property(TEST compute_transaction_test PROPERTY LABELS nonparallelizable_tests) add_test(NAME read-only-trx-basic-test COMMAND tests/read_only_trx_test.py -v -p 2 -n 3 --read-only-threads 0 ${UNSHARE} WORKING_DIRECTORY ${CMAKE_BINARY_DIR}) set_property(TEST read-only-trx-basic-test PROPERTY LABELS nonparallelizable_tests) -add_test(NAME read-only-trx-parallel-test COMMAND tests/read_only_trx_test.py -v -p 2 -n 3 --read-only-threads 6 --num-test-runs 3 ${UNSHARE} WORKING_DIRECTORY ${CMAKE_BINARY_DIR}) +add_test(NAME read-only-trx-parallel-test COMMAND tests/read_only_trx_test.py -v -p 2 -n 3 --read-only-threads 128 --num-test-runs 3 ${UNSHARE} WORKING_DIRECTORY ${CMAKE_BINARY_DIR}) set_property(TEST read-only-trx-parallel-test PROPERTY LABELS nonparallelizable_tests) -add_test(NAME read-only-trx-parallel-eos-vm-oc-test COMMAND tests/read_only_trx_test.py -v -p 2 -n 3 --eos-vm-oc-enable all --read-only-threads 6 --num-test-runs 3 ${UNSHARE} WORKING_DIRECTORY ${CMAKE_BINARY_DIR}) +add_test(NAME read-only-trx-parallel-eos-vm-oc-test COMMAND tests/read_only_trx_test.py -v -p 2 -n 3 --eos-vm-oc-enable all --read-only-threads 128 --num-test-runs 3 ${UNSHARE} WORKING_DIRECTORY ${CMAKE_BINARY_DIR}) set_property(TEST read-only-trx-parallel-eos-vm-oc-test PROPERTY LABELS nonparallelizable_tests) add_test(NAME read-only-trx-parallel-no-oc-test COMMAND tests/read_only_trx_test.py -v -p 2 -n 3 --eos-vm-oc-enable none --read-only-threads 6 --num-test-runs 2 ${UNSHARE} WORKING_DIRECTORY ${CMAKE_BINARY_DIR}) set_property(TEST read-only-trx-parallel-no-oc-test PROPERTY LABELS nonparallelizable_tests) diff --git a/tests/PerformanceHarness/README.md b/tests/PerformanceHarness/README.md index 4b267fd1ca..3178aa9e51 100644 --- a/tests/PerformanceHarness/README.md +++ b/tests/PerformanceHarness/README.md @@ -8,7 +8,7 @@ The `PerformanceTest`'s main goal is to measure current peak performance metrics The `PerformanceTestBasic` test performs a single basic performance test that targets a configurable TPS target and, if successful, reports statistics on performance metrics measured during the test. It configures and launches a blockchain test environment, creates wallets and accounts for testing, and configures and launches transaction generators for creating specific transaction load in the ecosystem. Finally it analyzes the performance of the system under the configuration through log analysis and chain queries and produces a [Performance Test Basic Report](#performance-test-basic-report). -The `launch_generators.py` support script provides a means to easily calculate and spawn the number of transaction generator instances to generate a given target TPS, distributing generation load between the instances in a fair manner such that the aggregate load meets the requested test load. +The `TransactionGeneratorsLauncher` provides a means to easily calculate and spawn the number of transaction generator instances to generate a given target TPS, distributing generation load between the instances in a fair manner such that the aggregate load meets the requested test load. The `log_reader.py` support script is used primarily to analyze `nodeos` log files to glean information about generated blocks and transactions within those blocks after a test has concluded. This information is used to produce the performance test report. diff --git a/tests/PerformanceHarness/performance_test.py b/tests/PerformanceHarness/performance_test.py index 797654fc3a..4332450304 100755 --- a/tests/PerformanceHarness/performance_test.py +++ b/tests/PerformanceHarness/performance_test.py @@ -49,6 +49,8 @@ class PtConfig: userTrxDataFile: Path=None endpointMode: str="p2p" opModeCmd: str="" + trxGenerator: Path=Path(".") + def __post_init__(self): self.opModeDesc = "Block Producer Operational Mode" if self.opModeCmd == "testBpOpMode" else "API Node Operational Mode" if self.opModeCmd == "testApiOpMode" else "Undefined Operational Mode" @@ -112,7 +114,8 @@ def performPtbBinarySearch(self, clusterConfig: PerformanceTestBasic.ClusterConf scenarioResult = PerformanceTest.PerfTestSearchIndivResult(success=False, searchTarget=binSearchTarget, searchFloor=floor, searchCeiling=ceiling) ptbConfig = PerformanceTestBasic.PtbConfig(targetTps=binSearchTarget, testTrxGenDurationSec=self.ptConfig.testDurationSec, tpsLimitPerGenerator=self.ptConfig.tpsLimitPerGenerator, numAddlBlocksToPrune=self.ptConfig.numAddlBlocksToPrune, logDirRoot=logDirRoot, delReport=delReport, - quiet=quiet, userTrxDataFile=self.ptConfig.userTrxDataFile, endpointMode=self.ptConfig.endpointMode) + quiet=quiet, userTrxDataFile=self.ptConfig.userTrxDataFile, endpointMode=self.ptConfig.endpointMode, + trxGenerator=self.ptConfig.trxGenerator) myTest = PerformanceTestBasic(testHelperConfig=self.testHelperConfig, clusterConfig=clusterConfig, ptbConfig=ptbConfig, testNamePath=os.path.basename(sys.argv[0]).rsplit('.',maxsplit=1)[0]) myTest.runTest() @@ -154,7 +157,8 @@ def performPtbReverseLinearSearch(self, tpsInitial: int) -> TpsTestResult.PerfTe scenarioResult = PerformanceTest.PerfTestSearchIndivResult(success=False, searchTarget=searchTarget, searchFloor=absFloor, searchCeiling=absCeiling) ptbConfig = PerformanceTestBasic.PtbConfig(targetTps=searchTarget, testTrxGenDurationSec=self.ptConfig.testDurationSec, tpsLimitPerGenerator=self.ptConfig.tpsLimitPerGenerator, numAddlBlocksToPrune=self.ptConfig.numAddlBlocksToPrune, logDirRoot=self.loggingConfig.ptbLogsDirPath, delReport=self.ptConfig.delReport, - quiet=self.ptConfig.quiet, delPerfLogs=self.ptConfig.delPerfLogs, userTrxDataFile=self.ptConfig.userTrxDataFile, endpointMode=self.ptConfig.endpointMode) + quiet=self.ptConfig.quiet, delPerfLogs=self.ptConfig.delPerfLogs, userTrxDataFile=self.ptConfig.userTrxDataFile, endpointMode=self.ptConfig.endpointMode, + trxGenerator=self.ptConfig.trxGenerator) myTest = PerformanceTestBasic(testHelperConfig=self.testHelperConfig, clusterConfig=self.clusterConfig, ptbConfig=ptbConfig, testNamePath=os.path.basename(sys.argv[0]).rsplit('.',maxsplit=1)[0]) myTest.runTest() diff --git a/tests/PerformanceHarness/performance_test_basic.py b/tests/PerformanceHarness/performance_test_basic.py index 5189dc2530..d2d3b72fa0 100755 --- a/tests/PerformanceHarness/performance_test_basic.py +++ b/tests/PerformanceHarness/performance_test_basic.py @@ -173,7 +173,7 @@ class PtbConfig: userTrxDataFile: Path=None endpointMode: str="p2p" apiEndpoint: str=None - + trxGenerator: Path=Path(".") def __post_init__(self): self.expectedTransactionsSent = self.testTrxGenDurationSec * self.targetTps @@ -454,7 +454,7 @@ def configureConnections(): self.data.startBlock = self.waitForEmptyBlocks(self.validationNode, self.emptyBlockGoal) tpsTrxGensConfig = TpsTrxGensConfig(targetTps=self.ptbConfig.targetTps, tpsLimitPerGenerator=self.ptbConfig.tpsLimitPerGenerator, connectionPairList=self.connectionPairList) - self.cluster.trxGenLauncher = TransactionGeneratorsLauncher(chainId=chainId, lastIrreversibleBlockId=lib_id, contractOwnerAccount=self.clusterConfig.specifiedContract.account.name, + self.cluster.trxGenLauncher = TransactionGeneratorsLauncher(trxGenerator=self.ptbConfig.trxGenerator, chainId=chainId, lastIrreversibleBlockId=lib_id, contractOwnerAccount=self.clusterConfig.specifiedContract.account.name, accts=','.join(map(str, self.accountNames)), privateKeys=','.join(map(str, self.accountPrivKeys)), trxGenDurationSec=self.ptbConfig.testTrxGenDurationSec, logDir=self.trxGenLogDirPath, abiFile=abiFile, actionsData=actionsDataJson, actionsAuths=actionsAuthsJson, @@ -722,6 +722,7 @@ def _createBaseArgumentParser(defEndpointApiDef: str, defProdNodeCnt: int, defVa block log file is removed after startup.", default=None) ptbBaseParserGroup.add_argument("--http-threads", type=int, help=argparse.SUPPRESS if suppressHelp else "Number of worker threads in http thread pool", default=2) ptbBaseParserGroup.add_argument("--chain-state-db-size-mb", type=int, help=argparse.SUPPRESS if suppressHelp else "Maximum size (in MiB) of the chain state database", default=25600) + ptbBaseParserGroup.add_argument("--trx-generator", type=str, help=argparse.SUPPRESS if suppressHelp else "Transaction Generator executable", default="./tests/trx_generator/trx_generator") return ptbBaseParser diff --git a/tests/PerformanceHarnessScenarioRunner.py b/tests/PerformanceHarnessScenarioRunner.py index ac0a3d54d3..564ca0cf19 100755 --- a/tests/PerformanceHarnessScenarioRunner.py +++ b/tests/PerformanceHarnessScenarioRunner.py @@ -63,7 +63,8 @@ def main(): delPerfLogs=args.del_perf_logs, printMissingTransactions=args.print_missing_transactions, userTrxDataFile=Path(args.user_trx_data_file) if args.user_trx_data_file is not None else None, - endpointMode=args.endpoint_mode) + endpointMode=args.endpoint_mode, + trxGenerator=args.trx_generator) Utils.Print(f"testNamePath: {PurePath(PurePath(__file__).name).stem}") myTest = performance_test_basic.PerformanceTestBasic(testHelperConfig=testHelperConfig, clusterConfig=testClusterConfig, ptbConfig=ptbConfig, testNamePath=f"{PurePath(PurePath(__file__).name).stem}") elif args.scenario_type_sub_cmd == "findMax": @@ -85,7 +86,8 @@ def main(): calcNetThreads=args.calc_net_threads, userTrxDataFile=Path(args.user_trx_data_file) if args.user_trx_data_file is not None else None, endpointMode=args.endpoint_mode, - opModeCmd=args.op_mode_sub_cmd) + opModeCmd=args.op_mode_sub_cmd, + trxGenerator=args.trx_generator) myTest = performance_test.PerformanceTest(testHelperConfig=testHelperConfig, clusterConfig=testClusterConfig, ptConfig=ptConfig) else: diff --git a/tests/TestHarness/CMakeLists.txt b/tests/TestHarness/CMakeLists.txt index e35782ead6..1e00fbf567 100644 --- a/tests/TestHarness/CMakeLists.txt +++ b/tests/TestHarness/CMakeLists.txt @@ -9,7 +9,7 @@ configure_file(queries.py . COPYONLY) configure_file(transactions.py . COPYONLY) configure_file(libc.py . COPYONLY) configure_file(interfaces.py . COPYONLY) -configure_file(launch_transaction_generators.py . COPYONLY) +configure_file(TransactionGeneratorsLauncher.py . COPYONLY) configure_file(logging.py . COPYONLY) configure_file(depresolver.py . COPYONLY) configure_file(launcher.py . COPYONLY) diff --git a/tests/TestHarness/Cluster.py b/tests/TestHarness/Cluster.py index c028b7a632..fc0a6b055a 100644 --- a/tests/TestHarness/Cluster.py +++ b/tests/TestHarness/Cluster.py @@ -22,7 +22,7 @@ from .Node import BlockType from .Node import Node from .WalletMgr import WalletMgr -from .launch_transaction_generators import TransactionGeneratorsLauncher, TpsTrxGensConfig +from .TransactionGeneratorsLauncher import TransactionGeneratorsLauncher, TpsTrxGensConfig from .launcher import cluster_generator try: from .libc import unshare, CLONE_NEWNET @@ -1554,7 +1554,8 @@ def stripValues(lowestMaxes,greaterThan): def launchTrxGenerators(self, contractOwnerAcctName: str, acctNamesList: list, acctPrivKeysList: list, nodeId: int=0, tpsPerGenerator: int=10, numGenerators: int=1, durationSec: int=60, - waitToComplete:bool=False, abiFile=None, actionsData=None, actionsAuths=None): + waitToComplete:bool=False, abiFile=None, actionsData=None, actionsAuths=None, + trxGenerator=Path("./tests/trx_generator/trx_generator")): Utils.Print("Configure txn generators") node=self.getNode(nodeId) info = node.getInfo() @@ -1567,7 +1568,7 @@ def launchTrxGenerators(self, contractOwnerAcctName: str, acctNamesList: list, a self.preExistingFirstTrxFiles = glob.glob(f"{Utils.DataDir}/first_trx_*.txt") connectionPairList = [f"{self.host}:{self.getNodeP2pPort(nodeId)}"] tpsTrxGensConfig = TpsTrxGensConfig(targetTps=targetTps, tpsLimitPerGenerator=tpsLimitPerGenerator, connectionPairList=connectionPairList) - self.trxGenLauncher = TransactionGeneratorsLauncher(chainId=chainId, lastIrreversibleBlockId=lib_id, + self.trxGenLauncher = TransactionGeneratorsLauncher(trxGenerator=trxGenerator, chainId=chainId, lastIrreversibleBlockId=lib_id, contractOwnerAccount=contractOwnerAcctName, accts=','.join(map(str, acctNamesList)), privateKeys=','.join(map(str, acctPrivKeysList)), trxGenDurationSec=durationSec, logDir=Utils.DataDir, abiFile=abiFile, actionsData=actionsData, actionsAuths=actionsAuths, tpsTrxGensConfig=tpsTrxGensConfig, diff --git a/tests/TestHarness/launch_transaction_generators.py b/tests/TestHarness/TransactionGeneratorsLauncher.py similarity index 82% rename from tests/TestHarness/launch_transaction_generators.py rename to tests/TestHarness/TransactionGeneratorsLauncher.py index 353e361333..1285c1523a 100644 --- a/tests/TestHarness/launch_transaction_generators.py +++ b/tests/TestHarness/TransactionGeneratorsLauncher.py @@ -37,8 +37,9 @@ def __init__(self, targetTps: int, tpsLimitPerGenerator: int, connectionPairList class TransactionGeneratorsLauncher: - def __init__(self, chainId: int, lastIrreversibleBlockId: int, contractOwnerAccount: str, accts: str, privateKeys: str, trxGenDurationSec: int, logDir: str, + def __init__(self, trxGenerator: Path, chainId: int, lastIrreversibleBlockId: int, contractOwnerAccount: str, accts: str, privateKeys: str, trxGenDurationSec: int, logDir: str, abiFile: Path, actionsData, actionsAuths, tpsTrxGensConfig: TpsTrxGensConfig, endpointMode: str, apiEndpoint: str=None): + self.trxGenerator = trxGenerator self.chainId = chainId self.lastIrreversibleBlockId = lastIrreversibleBlockId self.contractOwnerAccount = contractOwnerAccount @@ -59,7 +60,8 @@ def launch(self, waitToComplete=True): for id, targetTps in enumerate(self.tpsTrxGensConfig.targetTpsPerGenList): connectionPair = self.tpsTrxGensConfig.connectionPairList[connectionPairIter].rsplit(":") popenStringList = [ - './tests/trx_generator/trx_generator', + # './tests/trx_generator/trx_generator', + f'{self.trxGenerator}', '--generator-id', f'{id}', '--chain-id', f'{self.chainId}', '--last-irreversible-block-id', f'{self.lastIrreversibleBlockId}', @@ -80,7 +82,7 @@ def launch(self, waitToComplete=True): popenStringList.extend(['--api-endpoint', f'{self.apiEndpoint}']) if Utils.Debug: - Print(f"Running trx_generator: {' '.join(popenStringList)}") + Print(f"Running transaction generator {self.trxGenerator} : {' '.join(popenStringList)}") self.subprocess_ret_codes.append(subprocess.Popen(popenStringList)) connectionPairIter = (connectionPairIter + 1) % len(self.tpsTrxGensConfig.connectionPairList) exitCodes=None @@ -97,6 +99,7 @@ def killAll(self): def parseArgs(): parser = argparse.ArgumentParser(add_help=False) parser.add_argument('-?', '--help', action='help', default=argparse.SUPPRESS, help=argparse._('show this help message and exit')) + parser.add_argument("trx_generator", type=str, help="The path to the transaction generator binary to excecute") parser.add_argument("chain_id", type=str, help="Chain ID") parser.add_argument("last_irreversible_block_id", type=str, help="Last irreversible block ID") parser.add_argument("contract_owner_account", type=str, help="Cluster contract owner account name") @@ -119,23 +122,3 @@ def parseArgs(): args = parser.parse_args() return args - -def main(): - args = parseArgs() - connectionPairList = sub('[\s+]', '', args.connection_pair_list) - connectionPairList = connectionPairList.rsplit(',') - - trxGenLauncher = TransactionGeneratorsLauncher(chainId=args.chain_id, lastIrreversibleBlockId=args.last_irreversible_block_id, - contractOwnerAccount=args.contract_owner_account, accts=args.accounts, - privateKeys=args.priv_keys, trxGenDurationSec=args.trx_gen_duration, logDir=args.log_dir, - abiFile=args.abi_file, actionsData=args.actions_data, actionsAuths=args.actions_auths, - tpsTrxGensConfig=TpsTrxGensConfig(targetTps=args.target_tps, tpsLimitPerGenerator=args.tps_limit_per_generator, - connectionPairList=connectionPairList), - endpointMode=args.endpoint_mode, apiEndpoint=args.api_endpoint) - - - exit_codes = trxGenLauncher.launch() - exit(exit_codes) - -if __name__ == '__main__': - main() diff --git a/tests/TestHarness/__init__.py b/tests/TestHarness/__init__.py index 0341b64a05..c2ba5ad0b3 100644 --- a/tests/TestHarness/__init__.py +++ b/tests/TestHarness/__init__.py @@ -1,4 +1,4 @@ -__all__ = ['Node', 'Cluster', 'WalletMgr', 'launcher', 'logging', 'depresolver', 'testUtils', 'TestHelper', 'queries', 'transactions', 'accounts', 'launch_transaction_generators', 'TransactionGeneratorsLauncher', 'TpsTrxGensConfig', 'core_symbol'] +__all__ = ['Node', 'Cluster', 'WalletMgr', 'launcher', 'logging', 'depresolver', 'testUtils', 'TestHelper', 'queries', 'transactions', 'accounts', 'TransactionGeneratorsLauncher', 'TpsTrxGensConfig', 'core_symbol'] from .Cluster import Cluster from .Node import Node @@ -9,5 +9,5 @@ from .testUtils import Utils from .Node import ReturnType from .TestHelper import TestHelper -from .launch_transaction_generators import TransactionGeneratorsLauncher, TpsTrxGensConfig +from .TransactionGeneratorsLauncher import TransactionGeneratorsLauncher, TpsTrxGensConfig from .core_symbol import CORE_SYMBOL diff --git a/tests/read_only_trx_test.py b/tests/read_only_trx_test.py index 661c3fded8..91f92a8a0b 100755 --- a/tests/read_only_trx_test.py +++ b/tests/read_only_trx_test.py @@ -148,12 +148,14 @@ def verifyOcVirtualMemory(): pageSize = os.sysconf("SC_PAGESIZE") actualVmSize = vmPages * pageSize - # When OC tierup is enabled, virtual memory used by IC is around + # In OC tierup a memory slice is 8GB; + # The main thread uses 529 slices; each read-only thread uses 11 slices. + # Total virtual memory is around: # 529 slices * 8GB (for main thread) + numReadOnlyThreads * 11 slices * 8GB - # This test verifies virtual memory taken by one read-only thread - # is not in the order of 1TB. - otherGB = 1000 # add 1TB for virtual memory used by others - expectedVmSize = ((529 * 8) + (args.read_only_threads * 88) + otherGB) * 1024 * 1024 * 1024 + # This test verifies virtual memory does not grow by the number + # of read-only thread in the order of TB. + memoryByOthersGB = 1000 # add 1TB for virtual memory used by others + expectedVmSize = ((529 * 8) + (args.read_only_threads * 88) + memoryByOthersGB) * 1024 * 1024 * 1024 Utils.Print(f"pid: {apiNode.pid}, actualVmSize: {actualVmSize}, expectedVmSize: {expectedVmSize}") assert(actualVmSize < expectedVmSize) except FileNotFoundError: diff --git a/tests/test_read_only_trx.cpp b/tests/test_read_only_trx.cpp index b371730681..b2e615ef14 100644 --- a/tests/test_read_only_trx.cpp +++ b/tests/test_read_only_trx.cpp @@ -12,7 +12,6 @@ #include #include #include -#include #include #include @@ -90,9 +89,9 @@ BOOST_AUTO_TEST_CASE(not_check_configs_if_no_read_only_threads) { void test_trxs_common(std::vector& specific_args, bool test_disable_tierup = false) { try { fc::scoped_exit> on_exit = []() { - chain::wasm_interface_collection::test_disable_tierup = false; + chain::wasm_interface::test_disable_tierup = false; }; - chain::wasm_interface_collection::test_disable_tierup = test_disable_tierup; + chain::wasm_interface::test_disable_tierup = test_disable_tierup; using namespace std::chrono_literals; fc::temp_directory temp;