diff --git a/golem/appconfig.py b/golem/appconfig.py index 1f49ef8df1..c43cd2b2ff 100644 --- a/golem/appconfig.py +++ b/golem/appconfig.py @@ -8,7 +8,6 @@ from golem.config.active import ENABLE_TALKBACK from golem.clientconfigdescriptor import ClientConfigDescriptor from golem.core.simpleconfig import SimpleConfig, ConfigEntry -from golem.core.variables import KEY_DIFFICULTY from golem.ranking.helper.trust_const import \ REQUESTING_TRUST, \ @@ -151,7 +150,6 @@ def load_config(cls, datadir, cfg_file_name=CONFIG_FILENAME): seed_port=START_PORT, seeds="", opt_peer_num=OPTIMAL_PEER_NUM, - key_difficulty=KEY_DIFFICULTY, # flags in_shutdown=0, accept_tasks=ACCEPT_TASKS, diff --git a/golem/client.py b/golem/client.py index 9f780689d0..0717e33c40 100644 --- a/golem/client.py +++ b/golem/client.py @@ -753,10 +753,6 @@ def get_dir_manager(self): def get_key_id(self): return self.keys_auth.key_id - @rpc_utils.expose('crypto.difficulty') - def get_difficulty(self): - return self.keys_auth.get_difficulty() - @rpc_utils.expose('net.ident.key') def get_node_key(self): key = self.node.key diff --git a/golem/clientconfigdescriptor.py b/golem/clientconfigdescriptor.py index 87dac44d38..5afb94dc05 100644 --- a/golem/clientconfigdescriptor.py +++ b/golem/clientconfigdescriptor.py @@ -1,8 +1,6 @@ import logging import typing -from golem.core.variables import KEY_DIFFICULTY - logger = logging.getLogger(__name__) @@ -21,7 +19,6 @@ def __init__(self): self.send_pings = 0 self.pings_interval = 0.0 self.use_ipv6 = 0 - self.key_difficulty = 0 self.use_upnp = 0 self.enable_talkback = 0 self.enable_monitor = 0 @@ -108,7 +105,6 @@ class ConfigApprover(object): to_int_opt = { 'seed_port', 'num_cores', 'opt_peer_num', 'p2p_session_timeout', 'task_session_timeout', 'pings_interval', 'max_results_sending_delay', - 'key_difficulty', } to_big_int_opt = { 'min_price', 'max_price', @@ -117,7 +113,6 @@ class ConfigApprover(object): 'getting_peers_interval', 'getting_tasks_interval', 'computing_trust', 'requesting_trust' } - max_opt = {'key_difficulty': KEY_DIFFICULTY} def __init__(self, config_desc): """ Create config approver class that keeps old config descriptor @@ -129,7 +124,6 @@ def __init__(self, config_desc): (self.to_int_opt, self._to_int), (self.to_big_int_opt, self._to_int), (self.to_float_opt, self._to_float), - (self.max_opt, self._max_value) ] self.config_desc = config_desc @@ -188,16 +182,3 @@ def _to_float(val, name): except ValueError: logger.warning("{} value '{}' is not a number".format(name, val)) return val - - @classmethod - def _max_value(cls, val, name): - """Try to set a maximum numeric value of val or the default value. - :param val: value that should be changed to float - :param str name: name of a config description option for logs - :return: max(val, min_value) or unchanged value if it's not possible - """ - try: - return max(val, cls.max_opt[name]) - except (KeyError, ValueError): - logger.warning('Cannot apply a minimum value to %r', name) - return val diff --git a/golem/core/keysauth.py b/golem/core/keysauth.py index c1e6d5cf61..65ca504bf9 100644 --- a/golem/core/keysauth.py +++ b/golem/core/keysauth.py @@ -53,9 +53,8 @@ class WrongPassword(Exception): class KeysAuth: """ Elliptical curves cryptographic authorization manager. Generates - private and public keys based on ECC (curve secp256k1) with specified - difficulty. Private key is stored in file. When this file not exist, is - broken or contain key below requested difficulty new key is generated. + private and public keys based on ECC (curve secp256k1). Private key is + stored in file. When this file not exist or is broken new key is generated. """ KEYS_SUBDIR = 'keys' @@ -64,29 +63,28 @@ class KeysAuth: key_id: str = "" ecc: ECCx = None - def __init__(self, datadir: str, private_key_name: str, password: str, - difficulty: int = 0) -> None: + def __init__( + self, + datadir: str, + private_key_name: str, + password: str, + ) -> None: """ Create new ECC keys authorization manager, load or create keys. :param datadir where to store files :param private_key_name: name of the file containing private key :param password: user password to protect private key - :param difficulty: - desired key difficulty level. It's a number of leading zeros in - binary representation of public key. Value in range <0, 255>. - 0 accepts all keys, 255 is nearly impossible. """ prv, pub = KeysAuth._load_or_generate_keys( - datadir, private_key_name, password, difficulty) + datadir, private_key_name, password) self._private_key = prv self.ecc = ECCx(prv) self.public_key = pub self.key_id = encode_hex(pub)[2:] self.eth_addr = pubkey_to_address(pub) - self.difficulty = KeysAuth.get_difficulty(self.key_id) @staticmethod def key_exists(datadir: str, private_key_name: str) -> bool: @@ -95,15 +93,17 @@ def key_exists(datadir: str, private_key_name: str) -> bool: return os.path.isfile(priv_key_path) @staticmethod - def _load_or_generate_keys(datadir: str, filename: str, password: str, - difficulty: int) -> Tuple[bytes, bytes]: + def _load_or_generate_keys( + datadir: str, + filename: str, + password: str, + ) -> Tuple[bytes, bytes]: keys_dir = KeysAuth._get_or_create_keys_dir(datadir) priv_key_path = os.path.join(keys_dir, filename) loaded_keys = KeysAuth._load_and_check_keys( priv_key_path, password, - difficulty, ) if loaded_keys: @@ -111,7 +111,7 @@ def _load_or_generate_keys(datadir: str, filename: str, password: str, priv_key, pub_key = loaded_keys else: logger.debug('No keys found, generating new one') - priv_key, pub_key = KeysAuth._generate_keys(difficulty) + priv_key, pub_key = KeysAuth._generate_keys() logger.debug('Generation completed, saving keys') KeysAuth._save_private_key(priv_key, priv_key_path, password) logger.debug('Keys stored succesfully') @@ -126,9 +126,10 @@ def _get_or_create_keys_dir(datadir: str) -> str: return keys_dir @staticmethod - def _load_and_check_keys(priv_key_path: str, - password: str, - difficulty: int) -> Optional[Tuple[bytes, bytes]]: + def _load_and_check_keys( + priv_key_path: str, + password: str, + ) -> Optional[Tuple[bytes, bytes]]: try: with open(priv_key_path, 'r') as f: keystore = f.read() @@ -143,29 +144,13 @@ def _load_and_check_keys(priv_key_path: str, pub_key = privtopub(priv_key) - if not KeysAuth.is_pubkey_difficult(pub_key, difficulty): - raise Exception("Loaded key is not difficult enough") - return priv_key, pub_key @staticmethod - def _generate_keys(difficulty: int) -> Tuple[bytes, bytes]: - from twisted.internet import reactor - reactor_started = reactor.running + def _generate_keys() -> Tuple[bytes, bytes]: logger.info("Generating new key pair") - started = time.time() - while True: - priv_key = mk_privkey(str(get_random_float())) - pub_key = privtopub(priv_key) - if KeysAuth.is_pubkey_difficult(pub_key, difficulty): - break - - # lets be responsive to reactor stop (eg. ^C hit by user) - if reactor_started and not reactor.running: - logger.warning("reactor stopped, aborting key generation ..") - raise Exception("aborting key generation") - - logger.info("Keys generated in %.2fs", time.time() - started) + priv_key = mk_privkey(str(get_random_float())) + pub_key = privtopub(priv_key) return priv_key, pub_key @staticmethod @@ -178,29 +163,6 @@ def _save_private_key(key, key_path, password: str): with open(key_path, 'w') as f: f.write(json.dumps(keystore)) - @staticmethod - def _count_max_hash(difficulty: int) -> int: - return 2 << (256 - difficulty - 1) - - @staticmethod - def is_pubkey_difficult(pub_key: Union[bytes, str], - difficulty: int) -> bool: - if isinstance(pub_key, str): - pub_key = decode_hex(pub_key) - return sha2(pub_key) < KeysAuth._count_max_hash(difficulty) - - def is_difficult(self, difficulty: int) -> bool: - return self.is_pubkey_difficult(self.public_key, difficulty) - - @staticmethod - def get_difficulty(key_id: str) -> int: - """ - Calculate given key difficulty. - This is more expensive to calculate than is_difficult, so use - the latter if possible. - """ - return int(math.floor(256 - math.log2(sha2(decode_hex(key_id))))) - def sign(self, data: bytes) -> bytes: """ Sign given data with ECDSA; diff --git a/golem/core/variables.py b/golem/core/variables.py index b1dc76916b..db2706f3bd 100644 --- a/golem/core/variables.py +++ b/golem/core/variables.py @@ -63,7 +63,6 @@ # Number of task headers transmitted per message TASK_HEADERS_LIMIT = 20 -KEY_DIFFICULTY = 14 # Maximum acceptable difference between node time and monitor time (seconds) MAX_TIME_DIFF = 10 diff --git a/golem/network/p2p/p2pservice.py b/golem/network/p2p/p2pservice.py index 3f17882876..9154318338 100644 --- a/golem/network/p2p/p2pservice.py +++ b/golem/network/p2p/p2pservice.py @@ -105,7 +105,6 @@ def __init__( self.last_challenge = "" self.base_difficulty = BASE_DIFFICULTY self.connect_to_known_hosts = connect_to_known_hosts - self.key_difficulty = config_desc.key_difficulty # Peers options self.peers = {} # active peers @@ -335,10 +334,9 @@ def add_peer(self, peer: PeerSession): """ key_id = peer.key_id logger.info( - "Adding peer. node=%s, address=%s:%s, key_difficulty=%r", + "Adding peer. node=%s, address=%s:%s", node_info_str(peer.node_name, key_id), peer.address, peer.port, - self.keys_auth.get_difficulty(key_id) ) with self._peer_lock: self.peers[key_id] = peer diff --git a/golem/network/p2p/peersession.py b/golem/network/p2p/peersession.py index 92e94a46a0..f70cf2d2a9 100644 --- a/golem/network/p2p/peersession.py +++ b/golem/network/p2p/peersession.py @@ -292,17 +292,6 @@ def _react_to_hello(self, msg): self.node_info = msg.node_info - if not KeysAuth.is_pubkey_difficult( - self.node_info.key, - self.p2p_service.key_difficulty): - logger.info( - "Key from %r (%s:%d) is not difficult enough (%d < %d).", - self.node_info.node_name, self.address, self.port, - KeysAuth.get_difficulty(self.node_info.key), - self.p2p_service.key_difficulty) - self.disconnect(message.base.Disconnect.REASON.KeyNotDifficult) - return - self.node_name = msg.node_info.node_name self.client_ver = msg.client_ver self.listen_port = msg.port diff --git a/golem/node.py b/golem/node.py index 31ad224060..283bf18e5b 100644 --- a/golem/node.py +++ b/golem/node.py @@ -224,7 +224,6 @@ def set_password(self, password: str) -> bool: datadir=self._datadir, private_key_name=PRIVATE_KEY, password=password, - difficulty=self._config_desc.key_difficulty, ) # When Golem is ready to use different Ethereum account for # payments and identity this should be called only when diff --git a/golem/task/tasksession.py b/golem/task/tasksession.py index 419686919d..76d6f72d1c 100644 --- a/golem/task/tasksession.py +++ b/golem/task/tasksession.py @@ -872,21 +872,6 @@ def _react_to_hello(self, msg): return send_hello = True - if not KeysAuth.is_pubkey_difficult( - self.key_id, - self.task_server.config_desc.key_difficulty): - logger.info( - "Key from %s (%s:%d) is not difficult enough (%d < %d).", - common.node_info_str( - msg.node_info.node_name, - msg.node_info.key, - ), - self.address, self.port, - KeysAuth.get_difficulty(self.key_id), - self.task_server.config_desc.key_difficulty) - self.disconnect(message.base.Disconnect.REASON.KeyNotDifficult) - return - nodeskeeper.store(msg.node_info) if send_hello: diff --git a/tests/golem/core/keygen_benchmark.py b/tests/golem/core/keygen_benchmark.py deleted file mode 100644 index 3351c85318..0000000000 --- a/tests/golem/core/keygen_benchmark.py +++ /dev/null @@ -1,21 +0,0 @@ -import os -import pytest - -from golem.core.keysauth import KeysAuth - - -def skip_benchmarks(): - if os.environ.get('benchmarks', False): - return False - return True - - -def key_gen(d: int): - return KeysAuth._generate_keys(difficulty=d) - - -@pytest.mark.skipif(skip_benchmarks(), reason="skip benchmarks by default") -@pytest.mark.parametrize("d", [10, 11, 12, 13, 14, 15, 16]) -@pytest.mark.benchmark(min_rounds=20, warmup=False) -def test_key_gen_speed(benchmark, d: int): - benchmark(key_gen, d) diff --git a/tests/golem/core/test_keysauth.py b/tests/golem/core/test_keysauth.py index 9f0b4a414b..1cb1f06b50 100644 --- a/tests/golem/core/test_keysauth.py +++ b/tests/golem/core/test_keysauth.py @@ -21,7 +21,6 @@ class TestKeysAuth(testutils.PEP8MixIn, testutils.TempDirFixture): def _create_keysauth( self, - difficulty=0, key_name=None, password='') -> KeysAuth: if key_name is None: @@ -30,7 +29,6 @@ def _create_keysauth( datadir=self.path, private_key_name=key_name, password=password, - difficulty=difficulty, ) def test_sha(self): @@ -60,44 +58,6 @@ def test_pubkey_suits_privkey(self): ka = self._create_keysauth() self.assertEqual(ka.public_key, privtopub(ka._private_key)) - def test_difficulty(self): - difficulty = 5 - ek = self._create_keysauth(difficulty) - assert difficulty <= ek.difficulty - assert ek.difficulty == KeysAuth.get_difficulty(ek.key_id) - - def test_get_difficulty(self): - difficulty = 8 - ek = self._create_keysauth(difficulty) - # first 8 bits of digest must be 0 - assert sha2(ek.public_key).to_bytes(256, 'big')[0] == 0 - assert KeysAuth.get_difficulty(ek.key_id) >= difficulty - assert KeysAuth.is_pubkey_difficult(ek.public_key, difficulty) - assert KeysAuth.is_pubkey_difficult(ek.key_id, difficulty) - - def test_exception_difficulty(self): - # given - lower_difficulty = 0 - req_difficulty = 7 - priv_key = str(random())[2:] - assert lower_difficulty < req_difficulty # just in case - - keys_dir = KeysAuth._get_or_create_keys_dir(self.path) - # create key that has difficulty lower than req_difficulty - while True: - ka = self._create_keysauth(lower_difficulty, priv_key) - if not ka.is_difficult(req_difficulty): - break - shutil.rmtree(keys_dir) # to enable keys regeneration - - assert KeysAuth.get_difficulty(ka.key_id) >= lower_difficulty - assert KeysAuth.get_difficulty(ka.key_id) < req_difficulty - - # then - with self.assertRaisesRegex(Exception, - "Loaded key is not difficult enough"): - self._create_keysauth(difficulty=req_difficulty, key_name=priv_key) - def test_save_keys(self): # given keys_dir = KeysAuth._get_or_create_keys_dir(self.path) @@ -118,9 +78,8 @@ def test_key_successful_load(self, logger): private_key = ek._private_key public_key = ek.public_key del ek - assert logger.info.call_count == 2 + assert logger.info.call_count == 1 assert logger.info.call_args_list[0][0][0] == 'Generating new key pair' - assert logger.info.call_args_list[1][0][0] == 'Keys generated in %.2fs' logger.reset_mock() # just in case # when @@ -202,27 +161,3 @@ def test_keystore(self): with self.assertRaises(WrongPassword): self._create_keysauth(key_name=key_name, password='wrong_pw') - - -class TestKeysAuthWithReactor(TestWithReactor): - - @patch('golem.core.keysauth.logger') - def test_generate_keys_stop_when_reactor_stopped(self, logger): - # given - from twisted.internet import threads - reactor = self._get_reactor() - - # when - threads.deferToThread(KeysAuth._generate_keys, difficulty=200) - - time.sleep(0.01) - reactor.stop() - time.sleep(0.01) - - # then - assert not reactor.running - assert logger.info.call_count == 1 - assert logger.info.call_args_list[0][0][0] == 'Generating new key pair' - assert logger.warning.call_count == 1 - assert logger.warning.call_args_list[0][0][0] == \ - 'reactor stopped, aborting key generation ..' diff --git a/tests/golem/network/p2p/test_peersession.py b/tests/golem/network/p2p/test_peersession.py index ee9813516e..2aaf305cfb 100644 --- a/tests/golem/network/p2p/test_peersession.py +++ b/tests/golem/network/p2p/test_peersession.py @@ -63,7 +63,6 @@ def __setup_handshake_server_test(self, send_mock) -> message.base.Hello: self.peer_session.conn.server.node_name = node.node_name self.peer_session.conn.server.keys_auth.key_id = \ key_id = 'server_key_id' - self.peer_session.conn.server.key_difficulty = 2 self.peer_session.conn.server.cur_port = port = random.randint(1, 50000) self.peer_session.conn_type = self.peer_session.CONN_TYPE_SERVER self.peer_session.start() @@ -137,19 +136,6 @@ def test_handshake_server_protoid(self, send_mock): message.base.Disconnect( reason=message.base.Disconnect.REASON.ProtocolVersion).slots()) - @patch('golem.network.transport.session.BasicSession.send') - @patch('golem.core.keysauth.KeysAuth.is_pubkey_difficult', - return_value=False) - def test_react_to_hello_key_not_difficult(self, is_difficult_fn, send_mock): - client_hello = self.__setup_handshake_server_test(send_mock) - - self.peer_session._react_to_hello(client_hello) - assert self.peer_session.key_id is None - - # should not throw - self.peer_session._react_to_rand_val( - message.base.RandVal(rand_val=self.peer_session.rand_val)) - @patch('golem.network.transport.session.BasicSession.send') def test_handshake_server_randval(self, send_mock): client_hello = self.__setup_handshake_server_test(send_mock) @@ -165,17 +151,6 @@ def test_handshake_server_randval(self, send_mock): message.base.Disconnect( reason=message.base.Disconnect.REASON.Unverified).slots()) - @patch('golem.network.transport.session.BasicSession.send') - def test_handshake_server_key_not_difficult(self, send_mock): - client_hello = self.__setup_handshake_server_test(send_mock) - client_hello.node_info.key = 'deadbeef' * 16 - self.peer_session._react_to_hello(client_hello) - - self.assertEqual( - send_mock.call_args_list[1][0][1].slots(), - message.base.Disconnect( - reason=message.base.Disconnect.REASON.KeyNotDifficult).slots()) - def __setup_handshake_client_test(self, send_mock): self.peer_session.conn.server.node = node = dt_p2p_factory.Node() self.peer_session.conn.server.node_name = node.node_name diff --git a/tests/golem/task/dummy/runner.py b/tests/golem/task/dummy/runner.py index f062459971..dd290e1d4e 100644 --- a/tests/golem/task/dummy/runner.py +++ b/tests/golem/task/dummy/runner.py @@ -68,7 +68,6 @@ def create_client(datadir, node_name): app_config = AppConfig.load_config(datadir) config_desc = ClientConfigDescriptor() config_desc.init_from_app_config(app_config) - config_desc.key_difficulty = 0 config_desc.use_upnp = False config_desc.node_name = node_name @@ -78,7 +77,6 @@ def create_client(datadir, node_name): datadir=datadir, private_key_name=faker.Faker().pystr(), password='password', - difficulty=config_desc.key_difficulty, ) database = Database( diff --git a/tests/golem/task/test_tasksession.py b/tests/golem/task/test_tasksession.py index c8bdcac938..45693ee769 100644 --- a/tests/golem/task/test_tasksession.py +++ b/tests/golem/task/test_tasksession.py @@ -360,7 +360,6 @@ def setUp(self): hyperdrive_client.HyperdriveClientOptions('1', 1.0) self.keys = KeysAuth( datadir=self.path, - difficulty=4, private_key_name='prv', password='', ) @@ -805,7 +804,6 @@ def setUp(self): self.ts.task_server.get_node_name.return_value = "Zażółć gęślą jaźń" requestor_keys = KeysAuth( datadir=self.path, - difficulty=4, private_key_name='prv', password='', ) @@ -816,7 +814,6 @@ def setUp(self): keys_auth = KeysAuth( datadir=self.path, - difficulty=4, private_key_name='prv', password='', ) @@ -866,7 +863,6 @@ def setUp(self): keys_auth = KeysAuth( datadir=self.path, - difficulty=4, private_key_name='prv', password='', ) @@ -1019,7 +1015,6 @@ def setUp(self): super().setUp() keys_auth = KeysAuth( datadir=self.path, - difficulty=4, private_key_name='prv', password='', ) @@ -1139,7 +1134,6 @@ def setUp(self): ), ) self.task_session = TaskSession(conn) - self.task_session.task_server.config_desc.key_difficulty = 1 self.task_session.task_server.sessions = {} @patch('golem.task.tasksession.TaskSession.send_hello') @@ -1186,30 +1180,10 @@ def test_react_to_hello_invalid_protocol_version( mock_disconnect.assert_called_once_with( message.base.Disconnect.REASON.ProtocolVersion) - def test_react_to_hello_key_not_difficult( - self, - _mock_store, - mock_disconnect, - *_, - ): - # given - self.task_session.task_server.config_desc.key_difficulty = 80 - - # when - with self.assertLogs(logger, level='INFO'): - self.task_session._react_to_hello(self.msg) - - # then - mock_disconnect.assert_called_with( - message.base.Disconnect.REASON.KeyNotDifficult, - ) - @patch('golem.task.tasksession.TaskSession.send_hello') - def test_react_to_hello_key_difficult(self, mock_hello, *_): + def test_react_to_hello(self, mock_hello, *_): # given - difficulty = 4 - self.task_session.task_server.config_desc.key_difficulty = difficulty - ka = KeysAuth(datadir=self.path, difficulty=difficulty, + ka = KeysAuth(datadir=self.path, private_key_name='prv', password='') self.msg.node_info.key = ka.key_id diff --git a/tests/test_clientconfigdescriptor.py b/tests/test_clientconfigdescriptor.py index 64be2d0b24..30838ce04f 100644 --- a/tests/test_clientconfigdescriptor.py +++ b/tests/test_clientconfigdescriptor.py @@ -1,6 +1,5 @@ from unittest import TestCase from golem.clientconfigdescriptor import ClientConfigDescriptor, ConfigApprover -from golem.core.variables import KEY_DIFFICULTY class TestClientConfigDescriptor(TestCase): @@ -16,7 +15,6 @@ def test_approve(self): config = ClientConfigDescriptor() config.num_cores = '1' config.computing_trust = '1' - config.key_difficulty = '0' approved_config = ConfigApprover(config).approve() @@ -25,11 +23,3 @@ def test_approve(self): assert isinstance(approved_config.computing_trust, float) assert approved_config.computing_trust == 1.0 - - assert isinstance(approved_config.key_difficulty, int) - assert approved_config.key_difficulty == KEY_DIFFICULTY - - def test_max_value_error(self): - key_error_var = 1 - assert ConfigApprover._max_value(key_error_var, 'does_not_exist') is \ - key_error_var