electrum

Electrum Bitcoin wallet
git clone https://git.parazyd.org/electrum
Log | Files | Refs | Submodules

commit bc0036297b906bc53ce3886ea146c752e47e1ce9
parent 2b93593e3fe278f62d4e1625437153813dde76ed
Author: SomberNight <somber.night@protonmail.com>
Date:   Thu, 28 Jun 2018 11:42:47 +0200

fast hmac on python 3.7+

Diffstat:
Mlib/bitcoin.py | 10+++++-----
Mlib/crypto.py | 9+++++++++
Mlib/ecc.py | 6+++---
3 files changed, 17 insertions(+), 8 deletions(-)

diff --git a/lib/bitcoin.py b/lib/bitcoin.py @@ -31,7 +31,7 @@ from . import version from . import segwit_addr from . import constants from . import ecc -from .crypto import Hash, sha256, hash_160 +from .crypto import Hash, sha256, hash_160, hmac_oneshot ################################## transactions @@ -149,7 +149,7 @@ def add_number_to_script(i: int) -> bytes: hash_encode = lambda x: bh2u(x[::-1]) hash_decode = lambda x: bfh(x)[::-1] -hmac_sha_512 = lambda x, y: hmac.new(x, y, hashlib.sha512).digest() +hmac_sha_512 = lambda x, y: hmac_oneshot(x, y, hashlib.sha512) def is_new_seed(x, prefix=version.SEED_PREFIX): @@ -565,7 +565,7 @@ def _CKD_priv(k, c, s, is_prime): raise BitcoinException('Impossible xprv (not within curve order)') from e cK = keypair.get_public_key_bytes(compressed=True) data = bytes([0]) + k + s if is_prime else cK + s - I = hmac.new(c, data, hashlib.sha512).digest() + I = hmac_oneshot(c, data, hashlib.sha512) I_left = ecc.string_to_number(I[0:32]) k_n = (I_left + ecc.string_to_number(k)) % ecc.CURVE_ORDER if I_left >= ecc.CURVE_ORDER or k_n == 0: @@ -589,7 +589,7 @@ def CKD_pub(cK, c, n): # helper function, callable with arbitrary string. # note: 's' does not need to fit into 32 bits here! (c.f. trustedcoin billing) def _CKD_pub(cK, c, s): - I = hmac.new(c, cK + s, hashlib.sha512).digest() + I = hmac_oneshot(c, cK + s, hashlib.sha512) pubkey = ecc.ECPrivkey(I[0:32]) + ecc.ECPubkey(cK) if pubkey.is_at_infinity(): raise ecc.InvalidECPointException() @@ -683,7 +683,7 @@ def xpub_from_xprv(xprv): def bip32_root(seed, xtype): - I = hmac.new(b"Bitcoin seed", seed, hashlib.sha512).digest() + I = hmac_oneshot(b"Bitcoin seed", seed, hashlib.sha512) master_k = I[0:32] master_c = I[32:] # create xprv first, as that will check if master_k is within curve order diff --git a/lib/crypto.py b/lib/crypto.py @@ -26,6 +26,7 @@ import base64 import os import hashlib +import hmac import pyaes @@ -140,3 +141,11 @@ def hash_160(x: bytes) -> bytes: from . import ripemd md = ripemd.new(sha256(x)) return md.digest() + + +def hmac_oneshot(key: bytes, msg: bytes, digest) -> bytes: + if hasattr(hmac, 'digest'): + # requires python 3.7+; faster + return hmac.digest(key, msg, digest) + else: + return hmac.new(key, msg, digest).digest() diff --git a/lib/ecc.py b/lib/ecc.py @@ -36,7 +36,7 @@ from ecdsa.ellipticcurve import Point from ecdsa.util import string_to_number, number_to_string from .util import bfh, bh2u, assert_bytes, print_error, to_bytes, InvalidPassword, profiler -from .crypto import (Hash, aes_encrypt_with_iv, aes_decrypt_with_iv) +from .crypto import (Hash, aes_encrypt_with_iv, aes_decrypt_with_iv, hmac_oneshot) from .ecc_fast import do_monkey_patching_of_python_ecdsa_internals_with_libsecp256k1 @@ -285,7 +285,7 @@ class ECPubkey(object): ciphertext = aes_encrypt_with_iv(key_e, iv, message) ephemeral_pubkey = ephemeral.get_public_key_bytes(compressed=True) encrypted = magic + ephemeral_pubkey + ciphertext - mac = hmac.new(key_m, encrypted, hashlib.sha256).digest() + mac = hmac_oneshot(key_m, encrypted, hashlib.sha256) return base64.b64encode(encrypted + mac) @@ -424,7 +424,7 @@ class ECPrivkey(ECPubkey): ecdh_key = (ephemeral_pubkey * self.secret_scalar).get_public_key_bytes(compressed=True) key = hashlib.sha512(ecdh_key).digest() iv, key_e, key_m = key[0:16], key[16:32], key[32:] - if mac != hmac.new(key_m, encrypted[:-32], hashlib.sha256).digest(): + if mac != hmac_oneshot(key_m, encrypted[:-32], hashlib.sha256): raise InvalidPassword() return aes_decrypt_with_iv(key_e, iv, ciphertext)