Skip to content
This repository has been archived by the owner on Oct 31, 2023. It is now read-only.

Remove key difficulty pow #4325

Merged
merged 1 commit into from
Jun 13, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 0 additions & 2 deletions golem/appconfig.py
Original file line number Diff line number Diff line change
Expand Up @@ -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, \
Expand Down Expand Up @@ -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,
Expand Down
4 changes: 0 additions & 4 deletions golem/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
19 changes: 0 additions & 19 deletions golem/clientconfigdescriptor.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
import logging
import typing

from golem.core.variables import KEY_DIFFICULTY

logger = logging.getLogger(__name__)


Expand All @@ -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
Expand Down Expand Up @@ -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',
Expand All @@ -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
Expand All @@ -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

Expand Down Expand Up @@ -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
82 changes: 22 additions & 60 deletions golem/core/keysauth.py
Original file line number Diff line number Diff line change
Expand Up @@ -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'

Expand All @@ -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:
Expand All @@ -95,23 +93,25 @@ 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:
logger.debug('Existing keys loaded')
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')
Expand All @@ -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()
Expand All @@ -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
Expand All @@ -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;
Expand Down
1 change: 0 additions & 1 deletion golem/core/variables.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
4 changes: 1 addition & 3 deletions golem/network/p2p/p2pservice.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down
11 changes: 0 additions & 11 deletions golem/network/p2p/peersession.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
1 change: 0 additions & 1 deletion golem/node.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
15 changes: 0 additions & 15 deletions golem/task/tasksession.py
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down
21 changes: 0 additions & 21 deletions tests/golem/core/keygen_benchmark.py

This file was deleted.

Loading