From 00619bf9cffed3914e7366ce8f7ff8ee61eaca4d Mon Sep 17 00:00:00 2001 From: Lin Huang Date: Thu, 17 Aug 2023 18:52:44 -0400 Subject: [PATCH 01/24] use single backend per thread --- .../eosio/chain/webassembly/eos-vm.hpp | 7 +++-- .../chain/webassembly/runtimes/eos-vm.cpp | 26 ++++++++++++------- 2 files changed, 21 insertions(+), 12 deletions(-) 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/webassembly/runtimes/eos-vm.cpp b/libraries/chain/webassembly/runtimes/eos-vm.cpp index e23f91b90e..13bbbf6801 100644 --- a/libraries/chain/webassembly/runtimes/eos-vm.cpp +++ b/libraries/chain/webassembly/runtimes/eos-vm.cpp @@ -129,14 +129,17 @@ 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) + // re-initialize backend from the instantiate module of the contract + _runtime->_bkend = *_instantiated_module; + // re-initialize exec ctx with instantiate module _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 other per apply data + _runtime->_bkend.reset_max_call_depth(); + _runtime->_bkend.reset_max_pages(); + _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 +147,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 +156,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 +164,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 +284,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 From 7eff62bf7b7e5223d11961175863ad1484f50107 Mon Sep 17 00:00:00 2001 From: Lin Huang Date: Fri, 18 Aug 2023 21:37:31 -0400 Subject: [PATCH 02/24] use single wasm_interface; remove wasm_interface_collection.hpp and wasm_interface_collection.cpp; simplify multi-threading wasm_interface code significantly --- libraries/chain/CMakeLists.txt | 1 - libraries/chain/apply_context.cpp | 1 - libraries/chain/controller.cpp | 25 ++-- .../chain/include/eosio/chain/controller.hpp | 3 +- .../include/eosio/chain/wasm_interface.hpp | 24 +++- .../eosio/chain/wasm_interface_collection.hpp | 65 --------- .../eosio/chain/wasm_interface_private.hpp | 54 ++++++- libraries/chain/wasm_interface.cpp | 53 ++++++- libraries/chain/wasm_interface_collection.cpp | 134 ------------------ libraries/testing/tester.cpp | 1 - tests/test_read_only_trx.cpp | 5 +- 11 files changed, 134 insertions(+), 232 deletions(-) delete mode 100644 libraries/chain/include/eosio/chain/wasm_interface_collection.hpp delete mode 100644 libraries/chain/wasm_interface_collection.cpp diff --git a/libraries/chain/CMakeLists.txt b/libraries/chain/CMakeLists.txt index e44014b39c..67f51fc8bf 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 a620336b31..ebfdf2ab84 100644 --- a/libraries/chain/controller.cpp +++ b/libraries/chain/controller.cpp @@ -26,7 +26,6 @@ #include #include #include -#include #include #include @@ -256,7 +255,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; @@ -315,7 +314,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, @@ -342,7 +341,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); }); @@ -2686,20 +2685,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; @@ -3400,7 +3405,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 5960853786..965f96628a 100644 --- a/libraries/chain/include/eosio/chain/controller.hpp +++ b/libraries/chain/include/eosio/chain/controller.hpp @@ -38,7 +38,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; @@ -349,7 +348,7 @@ namespace eosio { namespace chain { */ 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..b70efe5209 100644 --- a/libraries/chain/include/eosio/chain/wasm_interface.hpp +++ b/libraries/chain/include/eosio/chain/wasm_interface.hpp @@ -46,11 +46,15 @@ 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(); +#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 +65,29 @@ 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 + //, each evicted entry is provided to callback + 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); + // 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; +#endif + //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..541ae187c4 100644 --- a/libraries/chain/include/eosio/chain/wasm_interface_private.hpp +++ b/libraries/chain/include/eosio/chain/wasm_interface_private.hpp @@ -43,7 +43,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,6 +90,13 @@ 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; @@ -84,18 +115,23 @@ 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) { + void current_lib(uint32_t lib) { //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); } +#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 ) { @@ -148,6 +184,10 @@ namespace eosio { namespace chain { 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/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/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/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; From 1451b6c1c9b3f3a042f6985b89ef9060f75ec860 Mon Sep 17 00:00:00 2001 From: Lin Huang Date: Tue, 22 Aug 2023 18:12:29 -0400 Subject: [PATCH 03/24] simplify get_instantiated_module() and make common case faster --- .../eosio/chain/wasm_interface_private.hpp | 43 +++++++++---------- 1 file changed, 21 insertions(+), 22 deletions(-) diff --git a/libraries/chain/include/eosio/chain/wasm_interface_private.hpp b/libraries/chain/include/eosio/chain/wasm_interface_private.hpp index 541ae187c4..342cb554ba 100644 --- a/libraries/chain/include/eosio/chain/wasm_interface_private.hpp +++ b/libraries/chain/include/eosio/chain/wasm_interface_private.hpp @@ -137,31 +137,30 @@ struct eosvmoc_tier { { 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(it != wasm_instantiation_cache.end()) { + // An instantiated module's module should never be null. + assert(it->module); + return it->module; } - if(!it->module) { - if(!codeobject) - codeobject = &db.get(boost::make_tuple(code_hash, vm_type, vm_version)); + // Parse the contract WASM into an instantiated module and + // cache the instantiated 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); + }); - 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; } From 2773c5036419f4da4666095e2ff200c5c8f49900 Mon Sep 17 00:00:00 2001 From: Lin Huang Date: Tue, 22 Aug 2023 19:14:30 -0400 Subject: [PATCH 04/24] add a mutex to wasm_instantiation_cache --- .../eosio/chain/wasm_interface_private.hpp | 27 ++++++++++++++++++- 1 file changed, 26 insertions(+), 1 deletion(-) diff --git a/libraries/chain/include/eosio/chain/wasm_interface_private.hpp b/libraries/chain/include/eosio/chain/wasm_interface_private.hpp index 342cb554ba..fa976b6602 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; @@ -102,11 +104,16 @@ struct eosvmoc_tier { ~wasm_interface_impl() = default; bool is_code_cached(const digest_type& code_hash, const uint8_t& vm_type, const uint8_t& vm_version) const { + std::shared_lock 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) { @@ -116,7 +123,10 @@ struct eosvmoc_tier { // reports each code_hash and vm_version that will be erased to callback void current_lib(uint32_t lib) { - //anything last used before or on the LIB can be evicted + // 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); #ifdef EOSIO_EOS_VM_OC_RUNTIME_ENABLED @@ -135,6 +145,7 @@ struct eosvmoc_tier { 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 ) { + std::shared_lock r_lock(instantiation_cache_mutex); wasm_cache_index::iterator it = wasm_instantiation_cache.find( boost::make_tuple(code_hash, vm_type, vm_version) ); if(it != wasm_instantiation_cache.end()) { @@ -142,6 +153,19 @@ struct eosvmoc_tier { assert(it->module); return it->module; } + r_lock.unlock(); + + // Acquire a unique lock as we need to modify the cache + std::unique_lock rw_lock(instantiation_cache_mutex); + + // While waiting for aquiring the write lock, another thread might + // have already compiled the contract and it is ready for use. + // Check again if that's the case. + it = wasm_instantiation_cache.find(boost::make_tuple(code_hash, vm_type, vm_version) ); + if (it != wasm_instantiation_cache.end()) { + assert(it->module); + return it->module; + } // Parse the contract WASM into an instantiated module and // cache the instantiated module. @@ -183,6 +207,7 @@ struct eosvmoc_tier { const chainbase::database& db; const wasm_interface::vm_type wasm_runtime_time; + mutable std::shared_mutex instantiation_cache_mutex; #ifdef EOSIO_EOS_VM_OC_RUNTIME_ENABLED std::unique_ptr eosvmoc{nullptr}; // used by all threads From bec7ce87f73bf07e3d20bc567cc84b4e68b6af7a Mon Sep 17 00:00:00 2001 From: Lin Huang Date: Wed, 23 Aug 2023 11:16:49 -0400 Subject: [PATCH 05/24] lock wasm_instantiation_cache only when read only threads are processing transactions --- .../eosio/chain/wasm_interface_private.hpp | 77 ++++++++++++------- 1 file changed, 50 insertions(+), 27 deletions(-) diff --git a/libraries/chain/include/eosio/chain/wasm_interface_private.hpp b/libraries/chain/include/eosio/chain/wasm_interface_private.hpp index fa976b6602..555e67aca2 100644 --- a/libraries/chain/include/eosio/chain/wasm_interface_private.hpp +++ b/libraries/chain/include/eosio/chain/wasm_interface_private.hpp @@ -104,6 +104,8 @@ struct eosvmoc_tier { ~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. No need to check if we should + // lock or not. std::shared_lock 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(); @@ -142,41 +144,63 @@ struct eosvmoc_tier { } #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 ) + 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) { - std::shared_lock r_lock(instantiation_cache_mutex); - 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; + wasm_cache_index::iterator it; + 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. + it = wasm_instantiation_cache.find( boost::make_tuple(code_hash, vm_type, vm_version) ); + } else { + std::shared_lock g(instantiation_cache_mutex); + it = wasm_instantiation_cache.find( boost::make_tuple(code_hash, vm_type, vm_version) ); } - r_lock.unlock(); - // Acquire a unique lock as we need to modify the cache - std::unique_lock rw_lock(instantiation_cache_mutex); - - // While waiting for aquiring the write lock, another thread might - // have already compiled the contract and it is ready for use. - // Check again if that's the case. - 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; } - // Parse the contract WASM into an instantiated module and - // cache the instantiated module. + if (trx_context.control.is_write_window()) { + return build_and_get_instantiated_module(code_hash, vm_type, vm_version, trx_context); + } else { + // Use unique lock as we need to modify the cache + std::unique_lock g(instantiation_cache_mutex); + + // While waiting for aquiring the lock, another thread might + // have already compiled the contract and it is ready for use. + // Check if that's the case. + it = wasm_instantiation_cache.find(boost::make_tuple(code_hash, vm_type, vm_version) ); + if (it != wasm_instantiation_cache.end()) { + assert(it->module); + return it->module; + } + + return build_and_get_instantiated_module(code_hash, vm_type, vm_version, trx_context); + } + } + + // Locked by the caller if required. + const std::unique_ptr& build_and_get_instantiated_module( + const digest_type& code_hash, + const uint8_t& vm_type, + const uint8_t& vm_version, + transaction_context& trx_context ) + { 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; + wasm_cache_index::iterator 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(); }); @@ -184,7 +208,6 @@ struct eosvmoc_tier { 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; } From fd7d561602c01366dcbe93cd0dd2dc7fbd27ca10 Mon Sep 17 00:00:00 2001 From: Lin Huang Date: Wed, 23 Aug 2023 12:17:20 -0400 Subject: [PATCH 06/24] bump eos-vm to the head of eos_vm_single_wasmif --- libraries/eos-vm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/eos-vm b/libraries/eos-vm index 74dd3f0c5e..7d184fb359 160000 --- a/libraries/eos-vm +++ b/libraries/eos-vm @@ -1 +1 @@ -Subproject commit 74dd3f0c5e621c4e22b543b0f1aa2539a516c46f +Subproject commit 7d184fb359683ff8653ea0ac37f4fc10df8f2fe8 From bed6fbcb87b2770cdac8c0b24620188f8186748d Mon Sep 17 00:00:00 2001 From: Lin Huang Date: Sat, 26 Aug 2023 12:07:30 -0400 Subject: [PATCH 07/24] bump eos-vm to head of eos_vm_single_wasmif --- libraries/eos-vm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/eos-vm b/libraries/eos-vm index 7d184fb359..b79fd167ef 160000 --- a/libraries/eos-vm +++ b/libraries/eos-vm @@ -1 +1 @@ -Subproject commit 7d184fb359683ff8653ea0ac37f4fc10df8f2fe8 +Subproject commit b79fd167ef39dc147e148ad1d1604e0cb82e9dab From 6a49cbc94d24cc658e9fb24b97aaeb614fb1e5f3 Mon Sep 17 00:00:00 2001 From: Peter Oschwald Date: Wed, 30 Aug 2023 13:16:01 -0500 Subject: [PATCH 08/24] Make transaction generator a configurable option to PerformanceHarness. --- tests/PerformanceHarness/performance_test.py | 8 ++++++-- tests/PerformanceHarness/performance_test_basic.py | 5 +++-- tests/PerformanceHarnessScenarioRunner.py | 6 ++++-- tests/TestHarness/Cluster.py | 5 +++-- tests/TestHarness/launch_transaction_generators.py | 11 +++++++---- 5 files changed, 23 insertions(+), 12 deletions(-) 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/Cluster.py b/tests/TestHarness/Cluster.py index c028b7a632..6d42864d0b 100644 --- a/tests/TestHarness/Cluster.py +++ b/tests/TestHarness/Cluster.py @@ -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/launch_transaction_generators.py index 353e361333..22951108dc 100644 --- a/tests/TestHarness/launch_transaction_generators.py +++ b/tests/TestHarness/launch_transaction_generators.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") @@ -125,7 +128,7 @@ def main(): connectionPairList = sub('[\s+]', '', args.connection_pair_list) connectionPairList = connectionPairList.rsplit(',') - trxGenLauncher = TransactionGeneratorsLauncher(chainId=args.chain_id, lastIrreversibleBlockId=args.last_irreversible_block_id, + trxGenLauncher = TransactionGeneratorsLauncher(trxGenerator=args.trx_generator, 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, From d26a930fb8ad3efaed1fcd3d336650cf7da516a5 Mon Sep 17 00:00:00 2001 From: Peter Oschwald Date: Wed, 30 Aug 2023 13:35:13 -0500 Subject: [PATCH 09/24] Some cleanup from being included in TestHarness module. --- .../launch_transaction_generators.py | 20 ------------------- 1 file changed, 20 deletions(-) diff --git a/tests/TestHarness/launch_transaction_generators.py b/tests/TestHarness/launch_transaction_generators.py index 22951108dc..1285c1523a 100644 --- a/tests/TestHarness/launch_transaction_generators.py +++ b/tests/TestHarness/launch_transaction_generators.py @@ -122,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(trxGenerator=args.trx_generator, 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() From 9f32850ac304baca041ce92713081457010f850d Mon Sep 17 00:00:00 2001 From: Peter Oschwald Date: Wed, 30 Aug 2023 13:50:16 -0500 Subject: [PATCH 10/24] Rename and refactor launch_transactions_generator to TransactionGeneratorsLauncher. --- tests/TestHarness/CMakeLists.txt | 2 +- tests/TestHarness/Cluster.py | 2 +- ...saction_generators.py => TransactionGeneratorsLauncher.py} | 0 tests/TestHarness/__init__.py | 4 ++-- 4 files changed, 4 insertions(+), 4 deletions(-) rename tests/TestHarness/{launch_transaction_generators.py => TransactionGeneratorsLauncher.py} (100%) 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 6d42864d0b..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 diff --git a/tests/TestHarness/launch_transaction_generators.py b/tests/TestHarness/TransactionGeneratorsLauncher.py similarity index 100% rename from tests/TestHarness/launch_transaction_generators.py rename to tests/TestHarness/TransactionGeneratorsLauncher.py 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 From 599fda89825f6ba9c02bd791216a7d3a70b2f13f Mon Sep 17 00:00:00 2001 From: Peter Oschwald Date: Wed, 30 Aug 2023 14:41:20 -0500 Subject: [PATCH 11/24] Update documentation. --- tests/PerformanceHarness/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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. From 828b47e961d290e86c0594ca3af4f34cd19cfbef Mon Sep 17 00:00:00 2001 From: Lin Huang Date: Thu, 31 Aug 2023 08:55:02 -0400 Subject: [PATCH 12/24] update to use backend's share method --- libraries/chain/webassembly/runtimes/eos-vm.cpp | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/libraries/chain/webassembly/runtimes/eos-vm.cpp b/libraries/chain/webassembly/runtimes/eos-vm.cpp index 13bbbf6801..7a7fc91bba 100644 --- a/libraries/chain/webassembly/runtimes/eos-vm.cpp +++ b/libraries/chain/webassembly/runtimes/eos-vm.cpp @@ -129,15 +129,16 @@ class eos_vm_instantiated_module : public wasm_instantiated_module_interface { _instantiated_module(std::move(mod)) {} void apply(apply_context& context) override { - // re-initialize backend from the instantiate module of the contract - _runtime->_bkend = *_instantiated_module; - // re-initialize exec ctx with instantiate module + // initialize backend from 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())); // link exe ctx to backend _runtime->_bkend.set_context(&_runtime->_exec_ctx); - // set other per apply data + // 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()); apply_options opts; From 28aa45232621bcb59f071887a20f4c01787eb22e Mon Sep 17 00:00:00 2001 From: Lin Huang Date: Thu, 31 Aug 2023 11:39:38 -0400 Subject: [PATCH 13/24] incorporate review comments --- .../include/eosio/chain/wasm_interface.hpp | 11 ++-- .../eosio/chain/wasm_interface_private.hpp | 54 +++++++------------ .../chain/webassembly/runtimes/eos-vm.cpp | 3 +- 3 files changed, 23 insertions(+), 45 deletions(-) diff --git a/libraries/chain/include/eosio/chain/wasm_interface.hpp b/libraries/chain/include/eosio/chain/wasm_interface.hpp index b70efe5209..72f5cd3f23 100644 --- a/libraries/chain/include/eosio/chain/wasm_interface.hpp +++ b/libraries/chain/include/eosio/chain/wasm_interface.hpp @@ -54,6 +54,9 @@ namespace eosio { namespace chain { #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 @@ -66,19 +69,11 @@ namespace eosio { namespace chain { 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); //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); - // 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; -#endif - //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; diff --git a/libraries/chain/include/eosio/chain/wasm_interface_private.hpp b/libraries/chain/include/eosio/chain/wasm_interface_private.hpp index 555e67aca2..961b6dd27e 100644 --- a/libraries/chain/include/eosio/chain/wasm_interface_private.hpp +++ b/libraries/chain/include/eosio/chain/wasm_interface_private.hpp @@ -22,7 +22,7 @@ #include #include -#include +#include using namespace fc; using namespace eosio::chain::webassembly; @@ -95,7 +95,7 @@ struct eosvmoc_tier { #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"); + 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 @@ -104,9 +104,9 @@ struct eosvmoc_tier { ~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. No need to check if we should - // lock or not. - std::shared_lock g(instantiation_cache_mutex); + // 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(); } @@ -150,51 +150,33 @@ struct eosvmoc_tier { const uint8_t& vm_version, transaction_context& trx_context) { - wasm_cache_index::iterator it; 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. - it = wasm_instantiation_cache.find( boost::make_tuple(code_hash, vm_type, vm_version) ); + return get_or_build_instantiated_module(code_hash, vm_type, vm_version, trx_context); } else { - std::shared_lock g(instantiation_cache_mutex); - 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; - } - - if (trx_context.control.is_write_window()) { - return build_and_get_instantiated_module(code_hash, vm_type, vm_version, trx_context); - } else { - // Use unique lock as we need to modify the cache - std::unique_lock g(instantiation_cache_mutex); - - // While waiting for aquiring the lock, another thread might - // have already compiled the contract and it is ready for use. - // Check if that's the case. - it = wasm_instantiation_cache.find(boost::make_tuple(code_hash, vm_type, vm_version) ); - if (it != wasm_instantiation_cache.end()) { - assert(it->module); - return it->module; - } - - return build_and_get_instantiated_module(code_hash, vm_type, vm_version, trx_context); + std::lock_guard g(instantiation_cache_mutex); + return get_or_build_instantiated_module(code_hash, vm_type, vm_version, trx_context); } } // Locked by the caller if required. - const std::unique_ptr& build_and_get_instantiated_module( + 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)); - wasm_cache_index::iterator it = wasm_instantiation_cache.emplace( wasm_interface_impl::wasm_cache_entry { + it = wasm_instantiation_cache.emplace( wasm_interface_impl::wasm_cache_entry { .code_hash = code_hash, .last_block_num_used = UINT32_MAX, .module = nullptr, @@ -226,11 +208,11 @@ struct eosvmoc_tier { 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; - mutable std::shared_mutex instantiation_cache_mutex; #ifdef EOSIO_EOS_VM_OC_RUNTIME_ENABLED std::unique_ptr eosvmoc{nullptr}; // used by all threads diff --git a/libraries/chain/webassembly/runtimes/eos-vm.cpp b/libraries/chain/webassembly/runtimes/eos-vm.cpp index 7a7fc91bba..345e8cd94b 100644 --- a/libraries/chain/webassembly/runtimes/eos-vm.cpp +++ b/libraries/chain/webassembly/runtimes/eos-vm.cpp @@ -129,7 +129,8 @@ class eos_vm_instantiated_module : public wasm_instantiated_module_interface { _instantiated_module(std::move(mod)) {} void apply(apply_context& context) override { - // initialize backend from the instantiated module of the contract + // 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())); From 494738563dce2b95534227da80f859d96bfd0aa3 Mon Sep 17 00:00:00 2001 From: Lin Huang Date: Thu, 31 Aug 2023 21:25:32 -0400 Subject: [PATCH 14/24] bump eos-vm to the latest of eos_vm_single_wasmif (prevent invalid sharing of compiled mod in backend) --- libraries/eos-vm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/eos-vm b/libraries/eos-vm index b79fd167ef..23d897d38b 160000 --- a/libraries/eos-vm +++ b/libraries/eos-vm @@ -1 +1 @@ -Subproject commit b79fd167ef39dc147e148ad1d1604e0cb82e9dab +Subproject commit 23d897d38b8de8db59e164d762ede935255f990e From df98be0f80d96837a46b8ae343c9495713178cf3 Mon Sep 17 00:00:00 2001 From: Matt Witherspoon <32485495+spoonincode@users.noreply.github.com> Date: Mon, 4 Sep 2023 18:34:44 -0400 Subject: [PATCH 15/24] switch out COMPILE_FLAGS for INCLUDE_DIRECTORIES --- libraries/libfc/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/libfc/CMakeLists.txt b/libraries/libfc/CMakeLists.txt index 3975f2bd4d..859f4162df 100644 --- a/libraries/libfc/CMakeLists.txt +++ b/libraries/libfc/CMakeLists.txt @@ -102,7 +102,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 ) From 62de747499b89491ea35b63d19f72ecd61a01747 Mon Sep 17 00:00:00 2001 From: Matt Witherspoon <32485495+spoonincode@users.noreply.github.com> Date: Tue, 5 Sep 2023 10:20:06 -0400 Subject: [PATCH 16/24] wrap fclose() to avoid warning on latest glibc --- libraries/libfc/include/fc/io/cfile.hpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/libraries/libfc/include/fc/io/cfile.hpp b/libraries/libfc/include/fc/io/cfile.hpp index c09adf894d..9c9f97e637 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; + static void close_file(FILE* f) { + 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) From 1b0ecccf442a8899c485b1248d6a0862950b8a5f Mon Sep 17 00:00:00 2001 From: Matt Witherspoon <32485495+spoonincode@users.noreply.github.com> Date: Tue, 5 Sep 2023 10:56:35 -0400 Subject: [PATCH 17/24] use inline instead of static here --- libraries/libfc/include/fc/io/cfile.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/libfc/include/fc/io/cfile.hpp b/libraries/libfc/include/fc/io/cfile.hpp index 9c9f97e637..809fdf31b4 100644 --- a/libraries/libfc/include/fc/io/cfile.hpp +++ b/libraries/libfc/include/fc/io/cfile.hpp @@ -19,7 +19,7 @@ namespace fc { namespace detail { - static void close_file(FILE* f) { + inline void close_file(FILE* f) { fclose(f); } From 3b29ca4e8e2bb492064c66688810026340aedc26 Mon Sep 17 00:00:00 2001 From: Matt Witherspoon <32485495+spoonincode@users.noreply.github.com> Date: Tue, 5 Sep 2023 11:29:06 -0400 Subject: [PATCH 18/24] and noexcept it --- libraries/libfc/include/fc/io/cfile.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/libfc/include/fc/io/cfile.hpp b/libraries/libfc/include/fc/io/cfile.hpp index 809fdf31b4..7e79b59942 100644 --- a/libraries/libfc/include/fc/io/cfile.hpp +++ b/libraries/libfc/include/fc/io/cfile.hpp @@ -19,7 +19,7 @@ namespace fc { namespace detail { - inline void close_file(FILE* f) { + inline void close_file(FILE* f) noexcept { fclose(f); } From 8ee6fee9ca87f719c7cdaa86ac136782540da4df Mon Sep 17 00:00:00 2001 From: Matt Witherspoon <32485495+spoonincode@users.noreply.github.com> Date: Wed, 6 Sep 2023 18:33:41 -0400 Subject: [PATCH 19/24] add modexp tests from boringssl --- .../test/crypto/test_modular_arithmetic.cpp | 832 ++++++++++++++++++ 1 file changed, 832 insertions(+) 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); From 0eebbac98b98b2e55d01b826c52737db1ca20c00 Mon Sep 17 00:00:00 2001 From: Lin Huang Date: Thu, 7 Sep 2023 21:30:18 -0400 Subject: [PATCH 20/24] bump eos-vm to the head of main --- libraries/eos-vm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/eos-vm b/libraries/eos-vm index 23d897d38b..b06ac3d4c1 160000 --- a/libraries/eos-vm +++ b/libraries/eos-vm @@ -1 +1 @@ -Subproject commit 23d897d38b8de8db59e164d762ede935255f990e +Subproject commit b06ac3d4c171cfd0a0f8fd74752e4eab35f60cb0 From 8a571d88d8d7a3280cc0f85c20d0ba8fe7919128 Mon Sep 17 00:00:00 2001 From: Lin Huang Date: Fri, 8 Sep 2023 09:17:33 -0400 Subject: [PATCH 21/24] Increase maximum allowed number of read-only threads to 128 --- plugins/producer_plugin/producer_plugin.cpp | 4 +--- tests/CMakeLists.txt | 4 ++-- tests/read_only_trx_test.py | 12 +++++++----- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/plugins/producer_plugin/producer_plugin.cpp b/plugins/producer_plugin/producer_plugin.cpp index c8db42b9fe..dbebf6dff6 100644 --- a/plugins/producer_plugin/producer_plugin.cpp +++ b/plugins/producer_plugin/producer_plugin.cpp @@ -617,9 +617,7 @@ 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 71147aaa34..233824062b 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -133,9 +133,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/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: From 920f325d039c053bddd7ddbac3ed55f151b6d2a1 Mon Sep 17 00:00:00 2001 From: Lin Huang Date: Fri, 8 Sep 2023 11:02:30 -0400 Subject: [PATCH 22/24] Add comments explaining why max supported number of read-only threads can be increased --- plugins/producer_plugin/producer_plugin.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/plugins/producer_plugin/producer_plugin.cpp b/plugins/producer_plugin/producer_plugin.cpp index dbebf6dff6..bffdf69e4d 100644 --- a/plugins/producer_plugin/producer_plugin.cpp +++ b/plugins/producer_plugin/producer_plugin.cpp @@ -617,6 +617,12 @@ class producer_plugin_impl : public std::enable_shared_from_this _ro_thread_pool; fc::microseconds _ro_write_window_time_us{200000}; From 0b3cd1f6e5601f27917de0817a4cec261120b692 Mon Sep 17 00:00:00 2001 From: Lin Huang Date: Mon, 11 Sep 2023 15:04:29 -0400 Subject: [PATCH 23/24] prevent unnecessary lib<->head catchup transition changes --- plugins/net_plugin/net_plugin.cpp | 29 +++++++++++++++++++++-------- 1 file changed, 21 insertions(+), 8 deletions(-) diff --git a/plugins/net_plugin/net_plugin.cpp b/plugins/net_plugin/net_plugin.cpp index f7f5d5d51c..2dbe7bec70 100644 --- a/plugins/net_plugin/net_plugin.cpp +++ b/plugins/net_plugin/net_plugin.cpp @@ -240,6 +240,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 ); @@ -250,7 +256,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; } @@ -1892,7 +1898,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 ) @@ -1900,6 +1906,7 @@ namespace eosio { ,sync_req_span( span ) ,sync_peer_limit( sync_peer_limit ) ,sync_state(in_sync) + ,min_blocks_distance(min_blocks_distance) { } @@ -2155,7 +2162,7 @@ namespace eosio { c->peer_syncing_from_us = false; return; } - if (chain_info.head_num < msg.last_irreversible_block_num) { + if (chain_info.head_num + min_blocks_distance < msg.last_irreversible_block_num) { peer_ilog( c, "handshake lib ${lib}, head ${head}, head id ${id}.. sync 1, 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) ); @@ -2165,7 +2172,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) ); @@ -3989,10 +3996,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; @@ -4004,6 +4007,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() ), From 3869235888c78cde443c75e5d33d01b16b6196da Mon Sep 17 00:00:00 2001 From: Lin Huang Date: Mon, 11 Sep 2023 20:18:39 -0400 Subject: [PATCH 24/24] revert the change for my head vs peer lib check --- plugins/net_plugin/net_plugin.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/net_plugin/net_plugin.cpp b/plugins/net_plugin/net_plugin.cpp index 2dbe7bec70..13166ce0bf 100644 --- a/plugins/net_plugin/net_plugin.cpp +++ b/plugins/net_plugin/net_plugin.cpp @@ -2162,7 +2162,7 @@ namespace eosio { c->peer_syncing_from_us = false; return; } - if (chain_info.head_num + min_blocks_distance < msg.last_irreversible_block_num) { + if (chain_info.head_num < msg.last_irreversible_block_num) { peer_ilog( c, "handshake lib ${lib}, head ${head}, head id ${id}.. sync 1, 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) );