From 004acb906d33ea3a13c87b7b05c67a33e1d3e3d9 Mon Sep 17 00:00:00 2001 From: SomberNight Date: Tue, 4 Feb 2020 18:17:12 +0100 Subject: [PATCH] ecc: abstract away some usage of python-ecdsa: randrange --- electrum/daemon.py | 9 ++++----- electrum/ecc.py | 8 ++++---- electrum/mnemonic.py | 6 ++---- electrum/tests/test_bitcoin.py | 4 ++-- electrum/util.py | 7 +++++++ 5 files changed, 19 insertions(+), 15 deletions(-) diff --git a/electrum/daemon.py b/electrum/daemon.py index ab9bb67f1..65e95e9c1 100644 --- a/electrum/daemon.py +++ b/electrum/daemon.py @@ -30,7 +30,7 @@ import traceback import sys import threading from typing import Dict, Optional, Tuple, Iterable -from base64 import b64decode +from base64 import b64decode, b64encode from collections import defaultdict import aiohttp @@ -44,7 +44,7 @@ from aiorpcx import TaskGroup from .network import Network from .util import (json_decode, to_bytes, to_string, profiler, standardize_path, constant_time_compare) from .util import PR_PAID, PR_EXPIRED, get_request_status -from .util import log_exceptions, ignore_exceptions +from .util import log_exceptions, ignore_exceptions, randrange from .wallet import Wallet, Abstract_Wallet from .storage import WalletStorage from .wallet_db import WalletDB @@ -124,11 +124,10 @@ def get_rpc_credentials(config: SimpleConfig) -> Tuple[str, str]: rpc_password = config.get('rpcpassword', None) if rpc_user is None or rpc_password is None: rpc_user = 'user' - import ecdsa, base64 bits = 128 nbytes = bits // 8 + (bits % 8 > 0) - pw_int = ecdsa.util.randrange(pow(2, bits)) - pw_b64 = base64.b64encode( + pw_int = randrange(pow(2, bits)) + pw_b64 = b64encode( pw_int.to_bytes(nbytes, 'big'), b'-_') rpc_password = to_string(pw_b64, 'ascii') config.set_key('rpcuser', rpc_user) diff --git a/electrum/ecc.py b/electrum/ecc.py index 9fd0154bb..e7f27c05e 100644 --- a/electrum/ecc.py +++ b/electrum/ecc.py @@ -35,7 +35,7 @@ from ecdsa.curves import SECP256k1 from ecdsa.ellipticcurve import Point from ecdsa.util import string_to_number, number_to_string -from .util import bfh, bh2u, assert_bytes, to_bytes, InvalidPassword, profiler +from .util import bfh, bh2u, assert_bytes, to_bytes, InvalidPassword, profiler, randrange from .crypto import (sha256d, aes_encrypt_with_iv, aes_decrypt_with_iv, hmac_oneshot) from .ecc_fast import do_monkey_patching_of_python_ecdsa_internals_with_libsecp256k1 from . import msqr @@ -145,7 +145,7 @@ class _MyVerifyingKey(ecdsa.VerifyingKey): G = curve.generator order = G.order() # extract r,s from signature - r, s = util.sigdecode_string(sig, order) + r, s = get_r_and_s_from_sig_string(sig, order) # 1.1 x = r + (recid//2) * order # 1.3 @@ -299,7 +299,7 @@ class ECPubkey(object): raise Exception('Wrong encoding') ecdsa_point = self._pubkey.point verifying_key = _MyVerifyingKey.from_public_point(ecdsa_point, curve=SECP256k1) - verifying_key.verify_digest(sig_string, msg_hash, sigdecode=ecdsa.util.sigdecode_string) + verifying_key.verify_digest(sig_string, msg_hash, sigdecode=get_r_and_s_from_sig_string) def encrypt_message(self, message: bytes, magic: bytes = b'BIE1') -> bytes: """ @@ -416,7 +416,7 @@ class ECPrivkey(ECPubkey): @classmethod def generate_random_key(cls): - randint = ecdsa.util.randrange(CURVE_ORDER) + randint = randrange(CURVE_ORDER) ephemeral_exponent = number_to_string(randint, CURVE_ORDER) return ECPrivkey(ephemeral_exponent) diff --git a/electrum/mnemonic.py b/electrum/mnemonic.py index 6acc427cd..ea37d0a2c 100644 --- a/electrum/mnemonic.py +++ b/electrum/mnemonic.py @@ -28,9 +28,7 @@ import hashlib import unicodedata import string -import ecdsa - -from .util import resource_path, bfh, bh2u +from .util import resource_path, bfh, bh2u, randrange from .crypto import hmac_oneshot from . import version from .logging import Logger @@ -180,7 +178,7 @@ class Mnemonic(Logger): entropy = 1 while entropy < pow(2, n - bpw): # try again if seed would not contain enough words - entropy = ecdsa.util.randrange(pow(2, n)) + entropy = randrange(pow(2, n)) nonce = 0 while True: nonce += 1 diff --git a/electrum/tests/test_bitcoin.py b/electrum/tests/test_bitcoin.py index dac854eea..d182372c4 100644 --- a/electrum/tests/test_bitcoin.py +++ b/electrum/tests/test_bitcoin.py @@ -16,7 +16,7 @@ from electrum.bip32 import (BIP32Node, convert_bip32_intpath_to_strpath, from electrum.crypto import sha256d, SUPPORTED_PW_HASH_VERSIONS from electrum import ecc, crypto, constants from electrum.ecc import number_to_string, string_to_number -from electrum.util import bfh, bh2u, InvalidPassword +from electrum.util import bfh, bh2u, InvalidPassword, randrange from electrum.storage import WalletStorage from electrum.keystore import xtype_from_derivation @@ -103,7 +103,7 @@ class Test_bitcoin(ElectrumTestCase): def _do_test_crypto(self, message): G = ecc.generator() _r = G.order() - pvk = ecdsa.util.randrange(_r) + pvk = randrange(_r) Pub = pvk*G pubkey_c = Pub.get_public_key_bytes(True) diff --git a/electrum/util.py b/electrum/util.py index a2a80b90f..9555be489 100644 --- a/electrum/util.py +++ b/electrum/util.py @@ -47,6 +47,7 @@ from aiohttp_socks import SocksConnector, SocksVer from aiorpcx import TaskGroup import certifi import dns.resolver +import ecdsa from .i18n import _ from .logging import get_logger, Logger @@ -1266,3 +1267,9 @@ def resolve_dns_srv(host: str): 'port': srv.port, } return [dict_from_srv_record(srv) for srv in srv_records] + + +def randrange(bound: int) -> int: + """Return a random integer k such that 1 <= k < bound, uniformly + distributed across that range.""" + return ecdsa.util.randrange(bound)