Browse Source

replace electrum/ecc with electrum_ecc package

master
ThomasV 2 years ago committed by SomberNight
parent
commit
3721f04ac8
No known key found for this signature in database
GPG Key ID: B33B5F232C6271E9
  1. 1
      contrib/requirements/requirements.txt
  2. 3
      electrum/bip32.py
  3. 5
      electrum/bitcoin.py
  4. 4
      electrum/channel_db.py
  5. 6
      electrum/commands.py
  6. 3
      electrum/crypto.py
  7. 3
      electrum/descriptor.py
  8. 553
      electrum/ecc.py
  9. 194
      electrum/ecc_fast.py
  10. 4
      electrum/gui/qt/main_window.py
  11. 4
      electrum/gui/qt/new_channel_dialog.py
  12. 6
      electrum/keystore.py
  13. 3
      electrum/lnaddr.py
  14. 5
      electrum/lnchannel.py
  15. 3
      electrum/lnonion.py
  16. 5
      electrum/lnpeer.py
  17. 3
      electrum/lnsweep.py
  18. 3
      electrum/lntransport.py
  19. 5
      electrum/lnutil.py
  20. 4
      electrum/lnverifier.py
  21. 2
      electrum/lnworker.py
  22. 3
      electrum/paymentrequest.py
  23. 3
      electrum/plugins/cosigner_pool/qt.py
  24. 4
      electrum/plugins/ledger/ledger.py
  25. 3
      electrum/plugins/trezor/clientbase.py
  26. 4
      electrum/plugins/trustedcoin/trustedcoin.py
  27. 4
      electrum/storage.py
  28. 2
      electrum/submarine_swaps.py
  29. 4
      electrum/transaction.py
  30. 3
      electrum/wallet.py
  31. 8
      tests/test_bitcoin.py
  32. 3
      tests/test_descriptor.py
  33. 8
      tests/test_ecc.py
  34. 2
      tests/test_lnpeer.py
  35. 3
      tests/test_lntransport.py
  36. 3
      tests/test_lnutil.py
  37. 3
      tests/test_transaction.py

1
contrib/requirements/requirements.txt

@ -7,6 +7,7 @@ aiohttp_socks>=0.8.4
certifi certifi
attrs>=20.1.0 attrs>=20.1.0
jsonpatch jsonpatch
electrum_ecc
# Note that we also need the dnspython[DNSSEC] extra which pulls in cryptography, # Note that we also need the dnspython[DNSSEC] extra which pulls in cryptography,
# but as that is not pure-python it cannot be listed in this file! # but as that is not pure-python it cannot be listed in this file!

3
electrum/bip32.py

@ -7,9 +7,10 @@ import hashlib
import struct import struct
from typing import List, Tuple, NamedTuple, Union, Iterable, Sequence, Optional from typing import List, Tuple, NamedTuple, Union, Iterable, Sequence, Optional
import electrum_ecc as ecc
from .util import bfh, BitcoinException from .util import bfh, BitcoinException
from . import constants from . import constants
from . import ecc
from .crypto import hash_160, hmac_oneshot from .crypto import hash_160, hmac_oneshot
from .bitcoin import EncodeBase58Check, DecodeBase58Check from .bitcoin import EncodeBase58Check, DecodeBase58Check
from .logging import get_logger from .logging import get_logger

5
electrum/bitcoin.py

@ -28,11 +28,12 @@ from typing import List, Tuple, TYPE_CHECKING, Optional, Union, Sequence, Any
import enum import enum
from enum import IntEnum, Enum from enum import IntEnum, Enum
import electrum_ecc as ecc
from .util import bfh, BitcoinException, assert_bytes, to_bytes, inv_dict, is_hex_str, classproperty from .util import bfh, BitcoinException, assert_bytes, to_bytes, inv_dict, is_hex_str, classproperty
from . import version from . import version
from . import segwit_addr from . import segwit_addr
from . import constants from . import constants
from . import ecc
from .crypto import sha256d, sha256, hash_160, hmac_oneshot from .crypto import sha256d, sha256, hash_160, hmac_oneshot
if TYPE_CHECKING: if TYPE_CHECKING:
@ -854,7 +855,7 @@ def ecdsa_sign_usermessage(ec_privkey, message: Union[bytes, str], *, is_compres
return ec_privkey.ecdsa_sign_recoverable(msg32, is_compressed=is_compressed) return ec_privkey.ecdsa_sign_recoverable(msg32, is_compressed=is_compressed)
def verify_usermessage_with_address(address: str, sig65: bytes, message: bytes, *, net=None) -> bool: def verify_usermessage_with_address(address: str, sig65: bytes, message: bytes, *, net=None) -> bool:
from .ecc import ECPubkey from electrum_ecc import ECPubkey
assert_bytes(sig65, message) assert_bytes(sig65, message)
if net is None: net = constants.net if net is None: net = constants.net
h = sha256d(usermessage_magic(message)) h = sha256d(usermessage_magic(message))

4
electrum/channel_db.py

@ -36,6 +36,8 @@ from enum import IntEnum
import functools import functools
from aiorpcx import NetAddress from aiorpcx import NetAddress
import electrum_ecc as ecc
from electrum_ecc import ECPubkey
from .sql_db import SqlDB, sql from .sql_db import SqlDB, sql
from . import constants, util from . import constants, util
@ -45,8 +47,6 @@ from .lnutil import (LNPeerAddr, format_short_channel_id, ShortChannelID,
validate_features, IncompatibleOrInsaneFeatures, InvalidGossipMsg) validate_features, IncompatibleOrInsaneFeatures, InvalidGossipMsg)
from .lnverifier import LNChannelVerifier, verify_sig_for_channel_update from .lnverifier import LNChannelVerifier, verify_sig_for_channel_update
from .lnmsg import decode_msg from .lnmsg import decode_msg
from . import ecc
from .ecc import ECPubkey
from .crypto import sha256d from .crypto import sha256d
from .lnmsg import FailedToParseMsg from .lnmsg import FailedToParseMsg

6
electrum/commands.py

@ -40,7 +40,9 @@ from decimal import Decimal, InvalidOperation
from typing import Optional, TYPE_CHECKING, Dict, List from typing import Optional, TYPE_CHECKING, Dict, List
import os import os
from . import util, ecc import electrum_ecc as ecc
from . import util
from . import keystore from . import keystore
from .util import (bfh, format_satoshis, json_decode, json_normalize, from .util import (bfh, format_satoshis, json_decode, json_normalize,
is_hash256_str, is_hex_str, to_bytes, parse_max_spend, to_decimal, is_hash256_str, is_hex_str, to_bytes, parse_max_spend, to_decimal,
@ -627,7 +629,7 @@ class Commands:
# Add shared libs (.so/.dll), and non-pure-python dependencies. # Add shared libs (.so/.dll), and non-pure-python dependencies.
# Such deps can be installed in various ways - often via the Linux distro's pkg manager, # Such deps can be installed in various ways - often via the Linux distro's pkg manager,
# instead of using pip, hence it is useful to list them for debugging. # instead of using pip, hence it is useful to list them for debugging.
from . import ecc_fast from electrum_ecc import ecc_fast
ret.update(ecc_fast.version_info()) ret.update(ecc_fast.version_info())
from . import qrscanner from . import qrscanner
ret.update(qrscanner.version_info()) ret.update(qrscanner.version_info())

3
electrum/crypto.py

@ -31,10 +31,11 @@ import hashlib
import hmac import hmac
from typing import Union, Mapping, Optional from typing import Union, Mapping, Optional
import electrum_ecc as ecc
from .util import assert_bytes, InvalidPassword, to_bytes, to_string, WalletFileException, versiontuple from .util import assert_bytes, InvalidPassword, to_bytes, to_string, WalletFileException, versiontuple
from .i18n import _ from .i18n import _
from .logging import get_logger from .logging import get_logger
from . import ecc
_logger = get_logger(__name__) _logger = get_logger(__name__)

3
electrum/descriptor.py

@ -28,12 +28,13 @@ from typing import (
Union, Union,
) )
import electrum_ecc as ecc
from .bip32 import convert_bip32_strpath_to_intpath, BIP32Node, KeyOriginInfo, BIP32_PRIME from .bip32 import convert_bip32_strpath_to_intpath, BIP32Node, KeyOriginInfo, BIP32_PRIME
from . import bitcoin from . import bitcoin
from .bitcoin import construct_script, opcodes, construct_witness, taproot_output_script from .bitcoin import construct_script, opcodes, construct_witness, taproot_output_script
from . import constants from . import constants
from .crypto import hash_160, sha256 from .crypto import hash_160, sha256
from . import ecc
from . import segwit_addr from . import segwit_addr

553
electrum/ecc.py

@ -1,553 +0,0 @@
# -*- coding: utf-8 -*-
#
# Electrum - lightweight Bitcoin client
# Copyright (C) 2018-2024 The Electrum developers
#
# Permission is hereby granted, free of charge, to any person
# obtaining a copy of this software and associated documentation files
# (the "Software"), to deal in the Software without restriction,
# including without limitation the rights to use, copy, modify, merge,
# publish, distribute, sublicense, and/or sell copies of the Software,
# and to permit persons to whom the Software is furnished to do so,
# subject to the following conditions:
#
# The above copyright notice and this permission notice shall be
# included in all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.
import base64
import hashlib
import functools
import secrets
from typing import Union, Tuple, Optional
from ctypes import (
byref, c_char_p, c_size_t, create_string_buffer, cast,
)
from . import ecc_fast
from .ecc_fast import _libsecp256k1, SECP256K1_EC_UNCOMPRESSED, LibModuleMissing
def assert_bytes(x):
assert isinstance(x, (bytes, bytearray))
# Some unit tests need to create ECDSA sigs without grinding the R value (and just use RFC6979).
# see https://github.com/bitcoin/bitcoin/pull/13666
ENABLE_ECDSA_R_VALUE_GRINDING = True
def string_to_number(b: bytes) -> int:
return int.from_bytes(b, byteorder='big', signed=False)
def ecdsa_sig64_from_der_sig(der_sig: bytes) -> bytes:
r, s = get_r_and_s_from_ecdsa_der_sig(der_sig)
return ecdsa_sig64_from_r_and_s(r, s)
def ecdsa_der_sig_from_ecdsa_sig64(sig64: bytes) -> bytes:
r, s = get_r_and_s_from_ecdsa_sig64(sig64)
return ecdsa_der_sig_from_r_and_s(r, s)
def ecdsa_der_sig_from_r_and_s(r: int, s: int) -> bytes:
sig64 = (
int.to_bytes(r, length=32, byteorder="big") +
int.to_bytes(s, length=32, byteorder="big"))
sig = create_string_buffer(64)
ret = _libsecp256k1.secp256k1_ecdsa_signature_parse_compact(_libsecp256k1.ctx, sig, sig64)
if 1 != ret:
raise Exception("Bad signature")
ret = _libsecp256k1.secp256k1_ecdsa_signature_normalize(_libsecp256k1.ctx, sig, sig)
der_sig = create_string_buffer(80) # this much space should be enough
der_sig_size = c_size_t(len(der_sig))
ret = _libsecp256k1.secp256k1_ecdsa_signature_serialize_der(_libsecp256k1.ctx, der_sig, byref(der_sig_size), sig)
if 1 != ret:
raise Exception("failed to serialize DER sig")
der_sig_size = der_sig_size.value
return bytes(der_sig)[:der_sig_size]
def get_r_and_s_from_ecdsa_der_sig(der_sig: bytes) -> Tuple[int, int]:
assert isinstance(der_sig, bytes)
sig = create_string_buffer(64)
ret = _libsecp256k1.secp256k1_ecdsa_signature_parse_der(_libsecp256k1.ctx, sig, der_sig, len(der_sig))
if 1 != ret:
raise Exception("Bad signature")
ret = _libsecp256k1.secp256k1_ecdsa_signature_normalize(_libsecp256k1.ctx, sig, sig)
compact_signature = create_string_buffer(64)
_libsecp256k1.secp256k1_ecdsa_signature_serialize_compact(_libsecp256k1.ctx, compact_signature, sig)
r = int.from_bytes(compact_signature[:32], byteorder="big")
s = int.from_bytes(compact_signature[32:], byteorder="big")
return r, s
def get_r_and_s_from_ecdsa_sig64(sig64: bytes) -> Tuple[int, int]:
if not (isinstance(sig64, bytes) and len(sig64) == 64):
raise Exception("sig64 must be bytes, and 64 bytes exactly")
sig = create_string_buffer(64)
ret = _libsecp256k1.secp256k1_ecdsa_signature_parse_compact(_libsecp256k1.ctx, sig, sig64)
if 1 != ret:
raise Exception("Bad signature")
ret = _libsecp256k1.secp256k1_ecdsa_signature_normalize(_libsecp256k1.ctx, sig, sig)
compact_signature = create_string_buffer(64)
_libsecp256k1.secp256k1_ecdsa_signature_serialize_compact(_libsecp256k1.ctx, compact_signature, sig)
r = int.from_bytes(compact_signature[:32], byteorder="big")
s = int.from_bytes(compact_signature[32:], byteorder="big")
return r, s
def ecdsa_sig64_from_r_and_s(r: int, s: int) -> bytes:
sig64 = (
int.to_bytes(r, length=32, byteorder="big") +
int.to_bytes(s, length=32, byteorder="big"))
sig = create_string_buffer(64)
ret = _libsecp256k1.secp256k1_ecdsa_signature_parse_compact(_libsecp256k1.ctx, sig, sig64)
if 1 != ret:
raise Exception("Bad signature")
ret = _libsecp256k1.secp256k1_ecdsa_signature_normalize(_libsecp256k1.ctx, sig, sig)
compact_signature = create_string_buffer(64)
_libsecp256k1.secp256k1_ecdsa_signature_serialize_compact(_libsecp256k1.ctx, compact_signature, sig)
return bytes(compact_signature)
def _x_and_y_from_pubkey_bytes(pubkey: bytes) -> Tuple[int, int]:
assert isinstance(pubkey, bytes), f'pubkey must be bytes, not {type(pubkey)}'
pubkey_ptr = create_string_buffer(64)
ret = _libsecp256k1.secp256k1_ec_pubkey_parse(
_libsecp256k1.ctx, pubkey_ptr, pubkey, len(pubkey))
if 1 != ret:
raise InvalidECPointException(
f'public key could not be parsed or is invalid: {pubkey.hex()!r}')
pubkey_serialized = create_string_buffer(65)
pubkey_size = c_size_t(65)
_libsecp256k1.secp256k1_ec_pubkey_serialize(
_libsecp256k1.ctx, pubkey_serialized, byref(pubkey_size), pubkey_ptr, SECP256K1_EC_UNCOMPRESSED)
pubkey_serialized = bytes(pubkey_serialized)
assert pubkey_serialized[0] == 0x04, pubkey_serialized
x = int.from_bytes(pubkey_serialized[1:33], byteorder='big', signed=False)
y = int.from_bytes(pubkey_serialized[33:65], byteorder='big', signed=False)
return x, y
class InvalidECPointException(Exception):
"""e.g. not on curve, or infinity"""
@functools.total_ordering
class ECPubkey(object):
def __init__(self, b: Optional[bytes]):
if b is not None:
assert isinstance(b, (bytes, bytearray)), f'pubkey must be bytes-like, not {type(b)}'
if isinstance(b, bytearray):
b = bytes(b)
self._x, self._y = _x_and_y_from_pubkey_bytes(b)
else:
self._x, self._y = None, None
@classmethod
def from_ecdsa_sig64(cls, sig64: bytes, recid: int, msg32: bytes) -> 'ECPubkey':
assert_bytes(sig64)
if len(sig64) != 64:
raise Exception(f'wrong encoding used for signature? len={len(sig64)} (should be 64)')
if not (0 <= recid <= 3):
raise ValueError('recid is {}, but should be 0 <= recid <= 3'.format(recid))
assert isinstance(msg32, (bytes, bytearray)), type(msg32)
assert len(msg32) == 32, len(msg32)
sig65 = create_string_buffer(65)
ret = _libsecp256k1.secp256k1_ecdsa_recoverable_signature_parse_compact(
_libsecp256k1.ctx, sig65, sig64, recid)
if 1 != ret:
raise Exception('failed to parse signature')
pubkey = create_string_buffer(64)
ret = _libsecp256k1.secp256k1_ecdsa_recover(_libsecp256k1.ctx, pubkey, sig65, msg32)
if 1 != ret:
raise InvalidECPointException('failed to recover public key')
return ECPubkey._from_libsecp256k1_pubkey_ptr(pubkey)
@classmethod
def from_ecdsa_sig65(cls, sig65: bytes, msg32: bytes) -> Tuple['ECPubkey', bool, Optional[str]]:
assert_bytes(sig65)
if len(sig65) != 65:
raise Exception(f'wrong encoding used for signature? len={len(sig65)} (should be 65)')
nV = sig65[0]
# as per BIP-0137:
# 27-30: p2pkh (uncompressed)
# 31-34: p2pkh (compressed)
# 35-38: p2wpkh-p2sh
# 39-42: p2wpkh
# However, the signatures we create do not respect this, and we instead always use 27-34,
# only distinguishing between compressed/uncompressed, so we treat those values as "any".
if not (27 <= nV <= 42):
raise Exception("Bad encoding")
txin_type_guess = None
compressed = True
if nV >= 39:
nV -= 12
txin_type_guess = "p2wpkh"
elif nV >= 35:
nV -= 8
txin_type_guess = "p2wpkh-p2sh"
elif nV >= 31:
nV -= 4
else:
compressed = False
recid = nV - 27
pubkey = cls.from_ecdsa_sig64(sig65[1:], recid, msg32)
return pubkey, compressed, txin_type_guess
@classmethod
def from_x_and_y(cls, x: int, y: int) -> 'ECPubkey':
_bytes = (b'\x04'
+ int.to_bytes(x, length=32, byteorder='big', signed=False)
+ int.to_bytes(y, length=32, byteorder='big', signed=False))
return ECPubkey(_bytes)
def get_public_key_bytes(self, compressed=True) -> bytes:
if self.is_at_infinity(): raise Exception('point is at infinity')
x = int.to_bytes(self.x(), length=32, byteorder='big', signed=False)
y = int.to_bytes(self.y(), length=32, byteorder='big', signed=False)
if compressed:
header = b'\x03' if self.y() & 1 else b'\x02'
return header + x
else:
header = b'\x04'
return header + x + y
def get_public_key_hex(self, compressed=True) -> str:
return self.get_public_key_bytes(compressed).hex()
def point(self) -> Tuple[Optional[int], Optional[int]]:
x = self.x()
y = self.y()
assert (x is None) == (y is None), f"either both x and y, or neither should be None. {(x, y)=}"
return x, y
def x(self) -> Optional[int]:
return self._x
def y(self) -> Optional[int]:
return self._y
def _to_libsecp256k1_pubkey_ptr(self):
"""pointer to `secp256k1_pubkey` C struct"""
pubkey_ptr = create_string_buffer(64)
pk_bytes = self.get_public_key_bytes(compressed=False)
ret = _libsecp256k1.secp256k1_ec_pubkey_parse(
_libsecp256k1.ctx, pubkey_ptr, pk_bytes, len(pk_bytes))
if 1 != ret:
raise Exception(f'public key could not be parsed or is invalid: {pk_bytes.hex()!r}')
return pubkey_ptr
def _to_libsecp256k1_xonly_pubkey_ptr(self):
"""pointer to `secp256k1_xonly_pubkey` C struct"""
if not ecc_fast.HAS_SCHNORR:
raise LibModuleMissing(
'libsecp256k1 library found but it was built '
'without required modules (--enable-module-schnorrsig --enable-module-extrakeys)')
pubkey_ptr = create_string_buffer(64)
pk_bytes = self.get_public_key_bytes(compressed=True)[1:]
ret = _libsecp256k1.secp256k1_xonly_pubkey_parse(
_libsecp256k1.ctx, pubkey_ptr, pk_bytes)
if 1 != ret:
raise Exception(f'public key could not be parsed or is invalid: {pk_bytes.hex()!r}')
return pubkey_ptr
@classmethod
def _from_libsecp256k1_pubkey_ptr(cls, pubkey) -> 'ECPubkey':
pubkey_serialized = create_string_buffer(65)
pubkey_size = c_size_t(65)
_libsecp256k1.secp256k1_ec_pubkey_serialize(
_libsecp256k1.ctx, pubkey_serialized, byref(pubkey_size), pubkey, SECP256K1_EC_UNCOMPRESSED)
return ECPubkey(bytes(pubkey_serialized))
def __repr__(self):
if self.is_at_infinity():
return f"<ECPubkey infinity>"
return f"<ECPubkey {self.get_public_key_hex()}>"
def __mul__(self, other: int):
if not isinstance(other, int):
raise TypeError('multiplication not defined for ECPubkey and {}'.format(type(other)))
other %= CURVE_ORDER
if self.is_at_infinity() or other == 0:
return POINT_AT_INFINITY
pubkey = self._to_libsecp256k1_pubkey_ptr()
ret = _libsecp256k1.secp256k1_ec_pubkey_tweak_mul(_libsecp256k1.ctx, pubkey, other.to_bytes(32, byteorder="big"))
if 1 != ret:
return POINT_AT_INFINITY
return ECPubkey._from_libsecp256k1_pubkey_ptr(pubkey)
def __rmul__(self, other: int):
return self * other
def __add__(self, other):
if not isinstance(other, ECPubkey):
raise TypeError('addition not defined for ECPubkey and {}'.format(type(other)))
if self.is_at_infinity(): return other
if other.is_at_infinity(): return self
pubkey1 = self._to_libsecp256k1_pubkey_ptr()
pubkey2 = other._to_libsecp256k1_pubkey_ptr()
pubkey_sum = create_string_buffer(64)
pubkey1 = cast(pubkey1, c_char_p)
pubkey2 = cast(pubkey2, c_char_p)
array_of_pubkey_ptrs = (c_char_p * 2)(pubkey1, pubkey2)
ret = _libsecp256k1.secp256k1_ec_pubkey_combine(_libsecp256k1.ctx, pubkey_sum, array_of_pubkey_ptrs, 2)
if 1 != ret:
return POINT_AT_INFINITY
return ECPubkey._from_libsecp256k1_pubkey_ptr(pubkey_sum)
def __eq__(self, other) -> bool:
if not isinstance(other, ECPubkey):
return False
return self.point() == other.point()
def __ne__(self, other):
return not (self == other)
def __hash__(self):
return hash(self.point())
def __lt__(self, other):
if not isinstance(other, ECPubkey):
raise TypeError('comparison not defined for ECPubkey and {}'.format(type(other)))
p1 = ((self.x() or 0), (self.y() or 0))
p2 = ((other.x() or 0), (other.y() or 0))
return p1 < p2
def ecdsa_verify_recoverable(self, sig65: bytes, msg32: bytes) -> bool:
try:
public_key, _compressed, _txin_type_guess = self.from_ecdsa_sig65(sig65, msg32)
except Exception:
return False
# check public key
if public_key != self:
return False
# check message
return self.ecdsa_verify(sig65[1:], msg32)
def ecdsa_verify(
self,
sig64: bytes,
msg32: bytes,
*,
enforce_low_s: bool = True, # policy/standardness rule
) -> bool:
assert_bytes(sig64)
if len(sig64) != 64:
return False
if not (isinstance(msg32, bytes) and len(msg32) == 32):
return False
sig = create_string_buffer(64)
ret = _libsecp256k1.secp256k1_ecdsa_signature_parse_compact(_libsecp256k1.ctx, sig, sig64)
if 1 != ret:
return False
if not enforce_low_s:
ret = _libsecp256k1.secp256k1_ecdsa_signature_normalize(_libsecp256k1.ctx, sig, sig)
pubkey = self._to_libsecp256k1_pubkey_ptr()
if 1 != _libsecp256k1.secp256k1_ecdsa_verify(_libsecp256k1.ctx, sig, msg32, pubkey):
return False
return True
def schnorr_verify(self, sig64: bytes, msg32: bytes) -> bool:
assert isinstance(sig64, bytes), type(sig64)
assert len(sig64) == 64, len(sig64)
assert isinstance(msg32, bytes), type(msg32)
assert len(msg32) == 32, len(msg32)
if not ecc_fast.HAS_SCHNORR:
raise LibModuleMissing(
'libsecp256k1 library found but it was built '
'without required modules (--enable-module-schnorrsig --enable-module-extrakeys)')
msglen = 32
pubkey = self._to_libsecp256k1_xonly_pubkey_ptr()
if 1 != _libsecp256k1.secp256k1_schnorrsig_verify(_libsecp256k1.ctx, sig64, msg32, msglen, pubkey):
return False
return True
@classmethod
def order(cls) -> int:
return CURVE_ORDER
def is_at_infinity(self) -> bool:
return self == POINT_AT_INFINITY
@classmethod
def is_pubkey_bytes(cls, b: bytes) -> bool:
try:
ECPubkey(b)
return True
except Exception:
return False
def has_even_y(self) -> bool:
return self.y() % 2 == 0
GENERATOR = ECPubkey(bytes.fromhex('0479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798'
'483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8'))
CURVE_ORDER = 0xFFFFFFFF_FFFFFFFF_FFFFFFFF_FFFFFFFE_BAAEDCE6_AF48A03B_BFD25E8C_D0364141
POINT_AT_INFINITY = ECPubkey(None)
def is_secret_within_curve_range(secret: Union[int, bytes]) -> bool:
if isinstance(secret, bytes):
secret = string_to_number(secret)
return 0 < secret < CURVE_ORDER
class ECPrivkey(ECPubkey):
def __init__(self, privkey_bytes: bytes):
assert_bytes(privkey_bytes)
if len(privkey_bytes) != 32:
raise Exception('unexpected size for secret. should be 32 bytes, not {}'.format(len(privkey_bytes)))
secret = string_to_number(privkey_bytes)
if not is_secret_within_curve_range(secret):
raise InvalidECPointException('Invalid secret scalar (not within curve order)')
self.secret_scalar = secret
pubkey = GENERATOR * secret
super().__init__(pubkey.get_public_key_bytes(compressed=False))
@classmethod
def from_secret_scalar(cls, secret_scalar: int) -> 'ECPrivkey':
secret_bytes = int.to_bytes(secret_scalar, length=32, byteorder='big', signed=False)
return ECPrivkey(secret_bytes)
@classmethod
def from_arbitrary_size_secret(cls, privkey_bytes: bytes) -> 'ECPrivkey':
"""This method is only for legacy reasons. Do not introduce new code that uses it.
Unlike the default constructor, this method does not require len(privkey_bytes) == 32,
and the secret does not need to be within the curve order either.
"""
return ECPrivkey(cls.normalize_secret_bytes(privkey_bytes))
@classmethod
def normalize_secret_bytes(cls, privkey_bytes: bytes) -> bytes:
scalar = string_to_number(privkey_bytes) % CURVE_ORDER
if scalar == 0:
raise Exception('invalid EC private key scalar: zero')
privkey_32bytes = int.to_bytes(scalar, length=32, byteorder='big', signed=False)
return privkey_32bytes
def __repr__(self):
return f"<ECPrivkey {self.get_public_key_hex()}>"
@classmethod
def generate_random_key(cls) -> 'ECPrivkey':
randint = secrets.randbelow(CURVE_ORDER - 1) + 1
ephemeral_exponent = int.to_bytes(randint, length=32, byteorder='big', signed=False)
return ECPrivkey(ephemeral_exponent)
def get_secret_bytes(self) -> bytes:
return int.to_bytes(self.secret_scalar, length=32, byteorder='big', signed=False)
def ecdsa_sign(self, msg32: bytes, *, sigencode=None) -> bytes:
if not (isinstance(msg32, bytes) and len(msg32) == 32):
raise Exception("msg32 to be signed must be bytes, and 32 bytes exactly")
if sigencode is None:
sigencode = ecdsa_sig64_from_r_and_s
privkey_bytes = self.secret_scalar.to_bytes(32, byteorder="big")
nonce_function = None
sig = create_string_buffer(64)
def sign_with_extra_entropy(extra_entropy):
ret = _libsecp256k1.secp256k1_ecdsa_sign(
_libsecp256k1.ctx, sig, msg32, privkey_bytes,
nonce_function, extra_entropy)
if 1 != ret:
raise Exception('the nonce generation function failed, or the private key was invalid')
compact_signature = create_string_buffer(64)
_libsecp256k1.secp256k1_ecdsa_signature_serialize_compact(_libsecp256k1.ctx, compact_signature, sig)
r = int.from_bytes(compact_signature[:32], byteorder="big")
s = int.from_bytes(compact_signature[32:], byteorder="big")
return r, s
r, s = sign_with_extra_entropy(extra_entropy=None)
if ENABLE_ECDSA_R_VALUE_GRINDING:
counter = 0
while r >= 2**255: # grind for low R value https://github.com/bitcoin/bitcoin/pull/13666
counter += 1
extra_entropy = counter.to_bytes(32, byteorder="little")
r, s = sign_with_extra_entropy(extra_entropy=extra_entropy)
sig64 = ecdsa_sig64_from_r_and_s(r, s)
if not self.ecdsa_verify(sig64, msg32):
raise Exception("sanity check failed: signature we just created does not verify!")
sig = sigencode(r, s)
return sig
def schnorr_sign(self, msg32: bytes, *, aux_rand32: bytes = None) -> bytes:
"""Creates a BIP-340 schnorr signature for the given message (hash)
and using the optional auxiliary random data.
note: msg32 is supposed to be a 32 byte hash of the message to be signed.
The BIP recommends using bip340_tagged_hash for hashing the message.
"""
assert isinstance(msg32, bytes), type(msg32)
assert len(msg32) == 32, len(msg32)
if aux_rand32 is None:
aux_rand32 = bytes(32)
assert isinstance(aux_rand32, bytes), type(aux_rand32)
assert len(aux_rand32) == 32, len(aux_rand32)
if not ecc_fast.HAS_SCHNORR:
raise LibModuleMissing(
'libsecp256k1 library found but it was built '
'without required modules (--enable-module-schnorrsig --enable-module-extrakeys)')
# construct "keypair" obj
privkey_bytes = self.secret_scalar.to_bytes(32, byteorder="big")
keypair = create_string_buffer(96)
ret = _libsecp256k1.secp256k1_keypair_create(_libsecp256k1.ctx, keypair, privkey_bytes)
if 1 != ret:
raise Exception('secret key was invalid')
# sign msg and verify sig
sig64 = create_string_buffer(64)
ret = _libsecp256k1.secp256k1_schnorrsig_sign32(
_libsecp256k1.ctx, sig64, msg32, keypair, aux_rand32)
sig64 = bytes(sig64)
if 1 != ret:
raise Exception('signing failure')
if not self.schnorr_verify(sig64, msg32):
raise Exception("sanity check failed: signature we just created does not verify!")
return sig64
def ecdsa_sign_recoverable(self, msg32: bytes, *, is_compressed: bool) -> bytes:
assert len(msg32) == 32, len(msg32)
def bruteforce_recid(sig64: bytes):
for recid in range(4):
sig65 = construct_ecdsa_sig65(sig64, recid, is_compressed=is_compressed)
if not self.ecdsa_verify_recoverable(sig65, msg32):
continue
return sig65, recid
else:
raise Exception("error: cannot sign message. no recid fits..")
sig64 = self.ecdsa_sign(msg32, sigencode=ecdsa_sig64_from_r_and_s)
sig65, recid = bruteforce_recid(sig64)
return sig65
def construct_ecdsa_sig65(sig64: bytes, recid: int, *, is_compressed: bool) -> bytes:
comp = 4 if is_compressed else 0
return bytes([27 + recid + comp]) + sig64

194
electrum/ecc_fast.py

@ -1,194 +0,0 @@
# Copyright (c) 2013-2018 Richard Kiss
# Copyright (c) 2018-2024 The Electrum developers
# Distributed under the MIT software license, see the accompanying
# file LICENCE or http://www.opensource.org/licenses/mit-license.php
#
# Originally based on pycoin:
# https://github.com/richardkiss/pycoin/blob/01b1787ed902df23f99a55deb00d8cd076a906fe/pycoin/ecdsa/native/secp256k1.py
import os
import sys
import traceback
import ctypes
from ctypes import (
byref, c_byte, c_int, c_uint, c_char_p, c_size_t, c_void_p, create_string_buffer,
CFUNCTYPE, POINTER, cast
)
from .logging import get_logger
_logger = get_logger(__name__)
SECP256K1_FLAGS_TYPE_MASK = ((1 << 8) - 1)
SECP256K1_FLAGS_TYPE_CONTEXT = (1 << 0)
SECP256K1_FLAGS_TYPE_COMPRESSION = (1 << 1)
# /** The higher bits contain the actual data. Do not use directly. */
SECP256K1_FLAGS_BIT_CONTEXT_VERIFY = (1 << 8)
SECP256K1_FLAGS_BIT_CONTEXT_SIGN = (1 << 9)
SECP256K1_FLAGS_BIT_COMPRESSION = (1 << 8)
# /** Flags to pass to secp256k1_context_create. */
SECP256K1_CONTEXT_VERIFY = (SECP256K1_FLAGS_TYPE_CONTEXT | SECP256K1_FLAGS_BIT_CONTEXT_VERIFY)
SECP256K1_CONTEXT_SIGN = (SECP256K1_FLAGS_TYPE_CONTEXT | SECP256K1_FLAGS_BIT_CONTEXT_SIGN)
SECP256K1_CONTEXT_NONE = (SECP256K1_FLAGS_TYPE_CONTEXT)
SECP256K1_EC_COMPRESSED = (SECP256K1_FLAGS_TYPE_COMPRESSION | SECP256K1_FLAGS_BIT_COMPRESSION)
SECP256K1_EC_UNCOMPRESSED = (SECP256K1_FLAGS_TYPE_COMPRESSION)
class LibModuleMissing(Exception): pass
def load_library():
global HAS_SCHNORR
# note: for a mapping between bitcoin-core/secp256k1 git tags and .so.V libtool version numbers,
# see https://github.com/bitcoin-core/secp256k1/pull/1055#issuecomment-1227505189
tested_libversions = [2, 1, 0, ] # try latest version first
libnames = []
if sys.platform == 'darwin':
for v in tested_libversions:
libnames.append(f"libsecp256k1.{v}.dylib")
elif sys.platform in ('windows', 'win32'):
for v in tested_libversions:
libnames.append(f"libsecp256k1-{v}.dll")
elif 'ANDROID_DATA' in os.environ:
libnames = ['libsecp256k1.so', ] # don't care about version number. we built w/e is available.
else: # desktop Linux and similar
for v in tested_libversions:
libnames.append(f"libsecp256k1.so.{v}")
# maybe we could fall back to trying "any" version? maybe guarded with an env var?
#libnames.append(f"libsecp256k1.so")
library_paths = []
for libname in libnames: # try local files in repo dir first
library_paths.append(os.path.join(os.path.dirname(__file__), libname))
for libname in libnames:
library_paths.append(libname)
exceptions = []
secp256k1 = None
for libpath in library_paths:
try:
secp256k1 = ctypes.cdll.LoadLibrary(libpath)
except BaseException as e:
exceptions.append(e)
else:
break
if not secp256k1:
_logger.error(f'libsecp256k1 library failed to load. exceptions: {repr(exceptions)}')
return None
try:
secp256k1.secp256k1_context_create.argtypes = [c_uint]
secp256k1.secp256k1_context_create.restype = c_void_p
secp256k1.secp256k1_context_randomize.argtypes = [c_void_p, c_char_p]
secp256k1.secp256k1_context_randomize.restype = c_int
secp256k1.secp256k1_ec_pubkey_create.argtypes = [c_void_p, c_void_p, c_char_p]
secp256k1.secp256k1_ec_pubkey_create.restype = c_int
secp256k1.secp256k1_ecdsa_sign.argtypes = [c_void_p, c_char_p, c_char_p, c_char_p, c_void_p, c_void_p]
secp256k1.secp256k1_ecdsa_sign.restype = c_int
secp256k1.secp256k1_ecdsa_verify.argtypes = [c_void_p, c_char_p, c_char_p, c_char_p]
secp256k1.secp256k1_ecdsa_verify.restype = c_int
secp256k1.secp256k1_ec_pubkey_parse.argtypes = [c_void_p, c_char_p, c_char_p, c_size_t]
secp256k1.secp256k1_ec_pubkey_parse.restype = c_int
secp256k1.secp256k1_ec_pubkey_serialize.argtypes = [c_void_p, c_char_p, c_void_p, c_char_p, c_uint]
secp256k1.secp256k1_ec_pubkey_serialize.restype = c_int
secp256k1.secp256k1_ecdsa_signature_parse_compact.argtypes = [c_void_p, c_char_p, c_char_p]
secp256k1.secp256k1_ecdsa_signature_parse_compact.restype = c_int
secp256k1.secp256k1_ecdsa_signature_normalize.argtypes = [c_void_p, c_char_p, c_char_p]
secp256k1.secp256k1_ecdsa_signature_normalize.restype = c_int
secp256k1.secp256k1_ecdsa_signature_serialize_compact.argtypes = [c_void_p, c_char_p, c_char_p]
secp256k1.secp256k1_ecdsa_signature_serialize_compact.restype = c_int
secp256k1.secp256k1_ecdsa_signature_parse_der.argtypes = [c_void_p, c_char_p, c_char_p, c_size_t]
secp256k1.secp256k1_ecdsa_signature_parse_der.restype = c_int
secp256k1.secp256k1_ecdsa_signature_serialize_der.argtypes = [c_void_p, c_char_p, c_void_p, c_char_p]
secp256k1.secp256k1_ecdsa_signature_serialize_der.restype = c_int
secp256k1.secp256k1_ec_pubkey_tweak_mul.argtypes = [c_void_p, c_char_p, c_char_p]
secp256k1.secp256k1_ec_pubkey_tweak_mul.restype = c_int
secp256k1.secp256k1_ec_pubkey_combine.argtypes = [c_void_p, c_char_p, c_void_p, c_size_t]
secp256k1.secp256k1_ec_pubkey_combine.restype = c_int
# --enable-module-recovery
try:
secp256k1.secp256k1_ecdsa_recover.argtypes = [c_void_p, c_char_p, c_char_p, c_char_p]
secp256k1.secp256k1_ecdsa_recover.restype = c_int
secp256k1.secp256k1_ecdsa_recoverable_signature_parse_compact.argtypes = [c_void_p, c_char_p, c_char_p, c_int]
secp256k1.secp256k1_ecdsa_recoverable_signature_parse_compact.restype = c_int
except (OSError, AttributeError):
raise LibModuleMissing('libsecp256k1 library found but it was built '
'without required module (--enable-module-recovery)')
# --enable-module-schnorrsig
try:
secp256k1.secp256k1_schnorrsig_sign32.argtypes = [c_void_p, c_char_p, c_char_p, c_char_p, c_char_p]
secp256k1.secp256k1_schnorrsig_sign32.restype = c_int
secp256k1.secp256k1_schnorrsig_verify.argtypes = [c_void_p, c_char_p, c_char_p, c_size_t, c_char_p]
secp256k1.secp256k1_schnorrsig_verify.restype = c_int
except (OSError, AttributeError):
_logger.warning(f"libsecp256k1 library found but it was built without desired module (--enable-module-schnorrsig)")
HAS_SCHNORR = False
# raise LibModuleMissing('libsecp256k1 library found but it was built '
# 'without required module (--enable-module-schnorrsig)')
# --enable-module-extrakeys
try:
secp256k1.secp256k1_xonly_pubkey_parse.argtypes = [c_void_p, c_char_p, c_char_p]
secp256k1.secp256k1_xonly_pubkey_parse.restype = c_int
secp256k1.secp256k1_xonly_pubkey_serialize.argtypes = [c_void_p, c_char_p, c_char_p]
secp256k1.secp256k1_xonly_pubkey_serialize.restype = c_int
secp256k1.secp256k1_keypair_create.argtypes = [c_void_p, c_char_p, c_char_p]
secp256k1.secp256k1_keypair_create.restype = c_int
except (OSError, AttributeError):
_logger.warning(f"libsecp256k1 library found but it was built without desired module (--enable-module-extrakeys)")
HAS_SCHNORR = False
# raise LibModuleMissing('libsecp256k1 library found but it was built '
# 'without required module (--enable-module-extrakeys)')
secp256k1.ctx = secp256k1.secp256k1_context_create(SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY)
ret = secp256k1.secp256k1_context_randomize(secp256k1.ctx, os.urandom(32))
if not ret:
_logger.error('secp256k1_context_randomize failed')
return None
return secp256k1
except (OSError, AttributeError) as e:
_logger.error(f'libsecp256k1 library was found and loaded but there was an error when using it: {repr(e)}')
return None
_libsecp256k1 = None
HAS_SCHNORR = True
try:
_libsecp256k1 = load_library()
except BaseException as e:
_logger.error(f'failed to load libsecp256k1: {repr(e)}')
if _libsecp256k1 is None:
# hard fail:
raise ImportError("Failed to load libsecp256k1")
def version_info() -> dict:
return {
"libsecp256k1.path": _libsecp256k1._name if _libsecp256k1 else None,
}

4
electrum/gui/qt/main_window.py

@ -47,9 +47,11 @@ from PyQt6.QtWidgets import (QMessageBox, QSystemTrayIcon, QTabWidget,
QWidget, QSizePolicy, QStatusBar, QToolTip, QWidget, QSizePolicy, QStatusBar, QToolTip,
QMenu, QToolButton) QMenu, QToolButton)
import electrum_ecc as ecc
import electrum import electrum
from electrum.gui import messages from electrum.gui import messages
from electrum import (keystore, ecc, constants, util, bitcoin, commands, from electrum import (keystore, constants, util, bitcoin, commands,
paymentrequest, lnutil) paymentrequest, lnutil)
from electrum.bitcoin import COIN, is_address, DummyAddress from electrum.bitcoin import COIN, is_address, DummyAddress
from electrum.plugin import run_hook, BasePlugin from electrum.plugin import run_hook, BasePlugin

4
electrum/gui/qt/new_channel_dialog.py

@ -1,12 +1,12 @@
from typing import TYPE_CHECKING, Optional from typing import TYPE_CHECKING, Optional
from PyQt6.QtWidgets import QLabel, QVBoxLayout, QGridLayout, QPushButton, QComboBox, QLineEdit, QSpacerItem, QWidget, QHBoxLayout from PyQt6.QtWidgets import QLabel, QVBoxLayout, QGridLayout, QPushButton, QComboBox, QLineEdit, QSpacerItem, QWidget, QHBoxLayout
import electrum_ecc as ecc
from electrum.i18n import _ from electrum.i18n import _
from electrum.transaction import PartialTxOutput, PartialTransaction from electrum.transaction import PartialTxOutput, PartialTransaction
from electrum.lnutil import MIN_FUNDING_SAT from electrum.lnutil import MIN_FUNDING_SAT
from electrum.lnworker import hardcoded_trampoline_nodes from electrum.lnworker import hardcoded_trampoline_nodes
from electrum import ecc
from electrum.util import NotEnoughFunds, NoDynamicFeeEstimates from electrum.util import NotEnoughFunds, NoDynamicFeeEstimates
from electrum.gui import messages from electrum.gui import messages

6
electrum/keystore.py

@ -32,7 +32,10 @@ from typing import Tuple, TYPE_CHECKING, Union, Sequence, Optional, Dict, List,
from functools import lru_cache, wraps from functools import lru_cache, wraps
from abc import ABC, abstractmethod from abc import ABC, abstractmethod
from . import bitcoin, ecc, constants, bip32 import electrum_ecc as ecc
from electrum_ecc import string_to_number
from . import bitcoin, constants, bip32
from .bitcoin import deserialize_privkey, serialize_privkey, BaseDecodeError from .bitcoin import deserialize_privkey, serialize_privkey, BaseDecodeError
from .transaction import Transaction, PartialTransaction, PartialTxInput, PartialTxOutput, TxInput from .transaction import Transaction, PartialTransaction, PartialTxInput, PartialTxOutput, TxInput
from .bip32 import (convert_bip32_strpath_to_intpath, BIP32_PRIME, from .bip32 import (convert_bip32_strpath_to_intpath, BIP32_PRIME,
@ -40,7 +43,6 @@ from .bip32 import (convert_bip32_strpath_to_intpath, BIP32_PRIME,
convert_bip32_intpath_to_strpath, is_xkey_consistent_with_key_origin_info, convert_bip32_intpath_to_strpath, is_xkey_consistent_with_key_origin_info,
KeyOriginInfo) KeyOriginInfo)
from .descriptor import PubkeyProvider from .descriptor import PubkeyProvider
from .ecc import string_to_number
from . import crypto from . import crypto
from .crypto import (pw_decode, pw_encode, sha256, sha256d, PW_HASH_VERSION_LATEST, from .crypto import (pw_decode, pw_encode, sha256, sha256d, PW_HASH_VERSION_LATEST,
SUPPORTED_PW_HASH_VERSIONS, UnsupportedPasswordHashVersion, hash_160, SUPPORTED_PW_HASH_VERSIONS, UnsupportedPasswordHashVersion, hash_160,

3
electrum/lnaddr.py

@ -10,12 +10,13 @@ from decimal import Decimal
from typing import Optional, TYPE_CHECKING, Type, Dict, Any, Union, Sequence, List, Tuple from typing import Optional, TYPE_CHECKING, Type, Dict, Any, Union, Sequence, List, Tuple
import random import random
import electrum_ecc as ecc
from .bitcoin import hash160_to_b58_address, b58_address_to_hash160, TOTAL_COIN_SUPPLY_LIMIT_IN_BTC from .bitcoin import hash160_to_b58_address, b58_address_to_hash160, TOTAL_COIN_SUPPLY_LIMIT_IN_BTC
from .segwit_addr import bech32_encode, bech32_decode, CHARSET, CHARSET_INVERSE, convertbits from .segwit_addr import bech32_encode, bech32_decode, CHARSET, CHARSET_INVERSE, convertbits
from . import segwit_addr from . import segwit_addr
from . import constants from . import constants
from .constants import AbstractNet from .constants import AbstractNet
from . import ecc
from .bitcoin import COIN from .bitcoin import COIN
if TYPE_CHECKING: if TYPE_CHECKING:

5
electrum/lnchannel.py

@ -33,8 +33,9 @@ import itertools
from aiorpcx import NetAddress from aiorpcx import NetAddress
import attr import attr
from . import ecc import electrum_ecc as ecc
from .ecc import ECPubkey from electrum_ecc import ECPubkey
from . import constants, util from . import constants, util
from .util import bfh, chunks, TxMinedInfo from .util import bfh, chunks, TxMinedInfo
from .invoices import PR_PAID from .invoices import PR_PAID

3
electrum/lnonion.py

@ -28,7 +28,8 @@ import hashlib
from typing import Sequence, List, Tuple, NamedTuple, TYPE_CHECKING, Dict, Any, Optional, Union from typing import Sequence, List, Tuple, NamedTuple, TYPE_CHECKING, Dict, Any, Optional, Union
from enum import IntEnum from enum import IntEnum
from . import ecc import electrum_ecc as ecc
from .crypto import sha256, hmac_oneshot, chacha20_encrypt from .crypto import sha256, hmac_oneshot, chacha20_encrypt
from .util import profiler, xor_bytes, bfh from .util import profiler, xor_bytes, bfh
from .lnutil import (get_ecdh, PaymentFailure, NUM_MAX_HOPS_IN_PAYMENT_PATH, from .lnutil import (get_ecdh, PaymentFailure, NUM_MAX_HOPS_IN_PAYMENT_PATH,

5
electrum/lnpeer.py

@ -13,13 +13,14 @@ from typing import Tuple, Dict, TYPE_CHECKING, Optional, Union, Set, Callable, A
from datetime import datetime from datetime import datetime
import functools import functools
import electrum_ecc as ecc
from electrum_ecc import ecdsa_sig64_from_r_and_s, ecdsa_der_sig_from_ecdsa_sig64, ECPubkey
import aiorpcx import aiorpcx
from aiorpcx import ignore_after from aiorpcx import ignore_after
from .crypto import sha256, sha256d from .crypto import sha256, sha256d
from . import bitcoin, util from . import bitcoin, util
from . import ecc
from .ecc import ecdsa_sig64_from_r_and_s, ecdsa_der_sig_from_ecdsa_sig64, ECPubkey
from . import constants from . import constants
from .util import (bfh, log_exceptions, ignore_exceptions, chunks, OldTaskGroup, from .util import (bfh, log_exceptions, ignore_exceptions, chunks, OldTaskGroup,
UnrelatedTransactionException, error_text_bytes_to_safe_str, AsyncHangDetector) UnrelatedTransactionException, error_text_bytes_to_safe_str, AsyncHangDetector)

3
electrum/lnsweep.py

@ -5,11 +5,12 @@
from typing import Optional, Dict, List, Tuple, TYPE_CHECKING, NamedTuple, Callable from typing import Optional, Dict, List, Tuple, TYPE_CHECKING, NamedTuple, Callable
from enum import Enum, auto from enum import Enum, auto
import electrum_ecc as ecc
from .util import bfh from .util import bfh
from .bitcoin import redeem_script_to_address, dust_threshold, construct_witness from .bitcoin import redeem_script_to_address, dust_threshold, construct_witness
from .invoices import PR_PAID from .invoices import PR_PAID
from . import descriptor from . import descriptor
from . import ecc
from .lnutil import (make_commitment_output_to_remote_address, make_commitment_output_to_local_witness_script, from .lnutil import (make_commitment_output_to_remote_address, make_commitment_output_to_local_witness_script,
derive_privkey, derive_pubkey, derive_blinded_pubkey, derive_blinded_privkey, derive_privkey, derive_pubkey, derive_blinded_pubkey, derive_blinded_privkey,
make_htlc_tx_witness, make_htlc_tx_with_open_channel, UpdateAddHtlc, make_htlc_tx_witness, make_htlc_tx_with_open_channel, UpdateAddHtlc,

3
electrum/lntransport.py

@ -11,10 +11,11 @@ from asyncio import StreamReader, StreamWriter
from typing import Optional from typing import Optional
from functools import cached_property from functools import cached_property
import electrum_ecc as ecc
from .crypto import sha256, hmac_oneshot, chacha20_poly1305_encrypt, chacha20_poly1305_decrypt from .crypto import sha256, hmac_oneshot, chacha20_poly1305_encrypt, chacha20_poly1305_decrypt
from .lnutil import (get_ecdh, privkey_to_pubkey, LightningPeerConnectionClosed, from .lnutil import (get_ecdh, privkey_to_pubkey, LightningPeerConnectionClosed,
HandshakeFailed, LNPeerAddr) HandshakeFailed, LNPeerAddr)
from . import ecc
from .util import MySocksProxy from .util import MySocksProxy

5
electrum/lnutil.py

@ -10,6 +10,8 @@ from typing import NamedTuple, List, Tuple, Mapping, Optional, TYPE_CHECKING, Un
import re import re
import sys import sys
import electrum_ecc as ecc
from electrum_ecc import CURVE_ORDER, ecdsa_sig64_from_der_sig, ECPubkey, string_to_number
import attr import attr
from aiorpcx import NetAddress from aiorpcx import NetAddress
@ -21,8 +23,7 @@ from .util import format_short_id as format_short_channel_id
from .crypto import sha256, pw_decode_with_version_and_mac from .crypto import sha256, pw_decode_with_version_and_mac
from .transaction import (Transaction, PartialTransaction, PartialTxInput, TxOutpoint, from .transaction import (Transaction, PartialTransaction, PartialTxInput, TxOutpoint,
PartialTxOutput, opcodes, TxOutput) PartialTxOutput, opcodes, TxOutput)
from .ecc import CURVE_ORDER, ecdsa_sig64_from_der_sig, ECPubkey, string_to_number from . import bitcoin, crypto, transaction
from . import ecc, bitcoin, crypto, transaction
from . import descriptor from . import descriptor
from .bitcoin import (redeem_script_to_address, address_to_script, from .bitcoin import (redeem_script_to_address, address_to_script,
construct_witness, construct_script) construct_witness, construct_script)

4
electrum/lnverifier.py

@ -28,10 +28,10 @@ import threading
from typing import TYPE_CHECKING, Dict, Set from typing import TYPE_CHECKING, Dict, Set
import aiorpcx import aiorpcx
import electrum_ecc as ecc
from electrum_ecc import ECPubkey
from . import bitcoin from . import bitcoin
from . import ecc
from .ecc import ECPubkey
from . import constants from . import constants
from .util import bfh, NetworkJobOnDefaultServer from .util import bfh, NetworkJobOnDefaultServer
from .lnutil import funding_output_script_from_keys, ShortChannelID from .lnutil import funding_output_script_from_keys, ShortChannelID

2
electrum/lnworker.py

@ -27,6 +27,7 @@ import aiohttp
import dns.resolver import dns.resolver
import dns.exception import dns.exception
from aiorpcx import run_in_thread, NetAddress, ignore_after from aiorpcx import run_in_thread, NetAddress, ignore_after
from electrum_ecc import ecdsa_der_sig_from_ecdsa_sig64
from . import constants, util from . import constants, util
from . import keystore from . import keystore
@ -51,7 +52,6 @@ from .logging import Logger
from .lntransport import LNTransport, LNResponderTransport, LNTransportBase from .lntransport import LNTransport, LNResponderTransport, LNTransportBase
from .lnpeer import Peer, LN_P2P_NETWORK_TIMEOUT from .lnpeer import Peer, LN_P2P_NETWORK_TIMEOUT
from .lnaddr import lnencode, LnAddr, lndecode from .lnaddr import lnencode, LnAddr, lndecode
from .ecc import ecdsa_der_sig_from_ecdsa_sig64
from .lnchannel import Channel, AbstractChannel from .lnchannel import Channel, AbstractChannel
from .lnchannel import ChannelState, PeerState, HTLCWithStatus from .lnchannel import ChannelState, PeerState, HTLCWithStatus
from .lnrater import LNRater from .lnrater import LNRater

3
electrum/paymentrequest.py

@ -31,6 +31,7 @@ import urllib.parse
import certifi import certifi
import aiohttp import aiohttp
import electrum_ecc as ecc
try: try:
@ -38,7 +39,7 @@ try:
except ImportError: except ImportError:
sys.exit("Error: could not find paymentrequest_pb2.py. Create it with 'contrib/generate_payreqpb2.sh'") sys.exit("Error: could not find paymentrequest_pb2.py. Create it with 'contrib/generate_payreqpb2.sh'")
from . import bitcoin, constants, ecc, util, transaction, x509, rsakey from . import bitcoin, constants, util, transaction, x509, rsakey
from .util import bfh, make_aiohttp_session, error_text_bytes_to_safe_str, get_running_loop from .util import bfh, make_aiohttp_session, error_text_bytes_to_safe_str, get_running_loop
from .invoices import Invoice, get_id_from_onchain_outputs from .invoices import Invoice, get_id_from_onchain_outputs
from .crypto import sha256 from .crypto import sha256

3
electrum/plugins/cosigner_pool/qt.py

@ -31,8 +31,9 @@ import ssl
from PyQt6.QtCore import QObject, pyqtSignal from PyQt6.QtCore import QObject, pyqtSignal
from PyQt6.QtWidgets import QPushButton from PyQt6.QtWidgets import QPushButton
import certifi import certifi
import electrum_ecc as ecc
from electrum import util, keystore, ecc, crypto from electrum import util, keystore, crypto
from electrum.transaction import Transaction, PartialTransaction, tx_from_any, SerializationError from electrum.transaction import Transaction, PartialTransaction, tx_from_any, SerializationError
from electrum.bip32 import BIP32Node from electrum.bip32 import BIP32Node
from electrum.plugin import BasePlugin, hook from electrum.plugin import BasePlugin, hook

4
electrum/plugins/ledger/ledger.py

@ -6,7 +6,9 @@ import base64
import hashlib import hashlib
from typing import Dict, List, Optional, Sequence, Tuple, TYPE_CHECKING from typing import Dict, List, Optional, Sequence, Tuple, TYPE_CHECKING
from electrum import bip32, constants, ecc import electrum_ecc as ecc
from electrum import bip32, constants
from electrum import descriptor from electrum import descriptor
from electrum.bip32 import BIP32Node, convert_bip32_intpath_to_strpath, normalize_bip32_derivation from electrum.bip32 import BIP32Node, convert_bip32_intpath_to_strpath, normalize_bip32_derivation
from electrum.bitcoin import EncodeBase58Check, is_b58_address, is_segwit_script_type, var_int from electrum.bitcoin import EncodeBase58Check, is_b58_address, is_segwit_script_type, var_int

3
electrum/plugins/trezor/clientbase.py

@ -1,7 +1,8 @@
import time import time
from struct import pack from struct import pack
from electrum import ecc import electrum_ecc as ecc
from electrum.i18n import _ from electrum.i18n import _
from electrum.util import UserCancelled, UserFacingException from electrum.util import UserCancelled, UserFacingException
from electrum.keystore import bip39_normalize_passphrase from electrum.keystore import bip39_normalize_passphrase

4
electrum/plugins/trustedcoin/trustedcoin.py

@ -32,7 +32,9 @@ from urllib.parse import quote
from aiohttp import ClientResponse from aiohttp import ClientResponse
from electrum import ecc, constants, keystore, version, bip32, bitcoin import electrum_ecc as ecc
from electrum import constants, keystore, version, bip32, bitcoin
from electrum.bip32 import BIP32Node, xpub_type from electrum.bip32 import BIP32Node, xpub_type
from electrum.crypto import sha256 from electrum.crypto import sha256
from electrum.transaction import PartialTxOutput, PartialTxInput, PartialTransaction, Transaction from electrum.transaction import PartialTxOutput, PartialTxInput, PartialTransaction, Transaction

4
electrum/storage.py

@ -31,7 +31,9 @@ import zlib
from enum import IntEnum from enum import IntEnum
from typing import Optional from typing import Optional
from . import ecc, crypto import electrum_ecc as ecc
from . import crypto
from .util import (profiler, InvalidPassword, WalletFileException, bfh, standardize_path, from .util import (profiler, InvalidPassword, WalletFileException, bfh, standardize_path,
test_read_write_permissions, os_chmod) test_read_write_permissions, os_chmod)

2
electrum/submarine_swaps.py

@ -8,10 +8,10 @@ import time
import attr import attr
import aiohttp import aiohttp
from electrum_ecc import ECPrivkey
from . import lnutil from . import lnutil
from .crypto import sha256, hash_160 from .crypto import sha256, hash_160
from .ecc import ECPrivkey
from .bitcoin import (script_to_p2wsh, opcodes, from .bitcoin import (script_to_p2wsh, opcodes,
construct_witness) construct_witness)
from .transaction import PartialTxInput, PartialTxOutput, PartialTransaction, Transaction, TxInput, TxOutpoint from .transaction import PartialTxInput, PartialTxOutput, PartialTransaction, Transaction, TxInput, TxOutpoint

4
electrum/transaction.py

@ -40,7 +40,9 @@ import itertools
import binascii import binascii
import copy import copy
from . import ecc, bitcoin, constants, segwit_addr, bip32 import electrum_ecc as ecc
from . import bitcoin, constants, segwit_addr, bip32
from .bip32 import BIP32Node from .bip32 import BIP32Node
from .i18n import _ from .i18n import _
from .util import profiler, to_bytes, bfh, chunks, is_hex_str, parse_max_spend from .util import profiler, to_bytes, bfh, chunks, is_hex_str, parse_max_spend

3
electrum/wallet.py

@ -47,6 +47,7 @@ import threading
import enum import enum
import asyncio import asyncio
import electrum_ecc as ecc
from aiorpcx import timeout_after, TaskTimeout, ignore_after, run_in_thread from aiorpcx import timeout_after, TaskTimeout, ignore_after, run_in_thread
from .i18n import _ from .i18n import _
@ -69,7 +70,7 @@ from .keystore import (load_keystore, Hardware_KeyStore, KeyStore, KeyStoreWithM
from .util import multisig_type, parse_max_spend from .util import multisig_type, parse_max_spend
from .storage import StorageEncryptionVersion, WalletStorage from .storage import StorageEncryptionVersion, WalletStorage
from .wallet_db import WalletDB from .wallet_db import WalletDB
from . import transaction, bitcoin, coinchooser, paymentrequest, ecc, bip32 from . import transaction, bitcoin, coinchooser, paymentrequest, bip32
from .transaction import (Transaction, TxInput, UnknownTxinType, TxOutput, from .transaction import (Transaction, TxInput, UnknownTxinType, TxOutput,
PartialTransaction, PartialTxInput, PartialTxOutput, TxOutpoint, Sighash) PartialTransaction, PartialTxInput, PartialTxOutput, TxOutpoint, Sighash)
from .plugin import run_hook from .plugin import run_hook

8
tests/test_bitcoin.py

@ -4,6 +4,8 @@ import json
import os import os
import sys import sys
import electrum_ecc as ecc
from electrum import bitcoin from electrum import bitcoin
from electrum.bitcoin import (public_key_to_p2pkh, address_from_private_key, from electrum.bitcoin import (public_key_to_p2pkh, address_from_private_key,
is_address, is_private_key, is_address, is_private_key,
@ -23,13 +25,11 @@ from electrum.bip32 import (BIP32Node, convert_bip32_intpath_to_strpath,
is_xpub, convert_bip32_strpath_to_intpath, is_xpub, convert_bip32_strpath_to_intpath,
normalize_bip32_derivation, is_all_public_derivation) normalize_bip32_derivation, is_all_public_derivation)
from electrum.crypto import sha256d, SUPPORTED_PW_HASH_VERSIONS from electrum.crypto import sha256d, SUPPORTED_PW_HASH_VERSIONS
from electrum import ecc, crypto, constants, bitcoin from electrum import crypto, constants, bitcoin
from electrum.util import bfh, InvalidPassword, randrange from electrum.util import bfh, InvalidPassword, randrange
from electrum.storage import WalletStorage from electrum.storage import WalletStorage
from electrum.keystore import xtype_from_derivation from electrum.keystore import xtype_from_derivation
from electrum import ecc_fast, crypto
from . import ElectrumTestCase from . import ElectrumTestCase
from . import FAST_TESTS from . import FAST_TESTS
@ -149,7 +149,7 @@ class Test_bitcoin(ElectrumTestCase):
def test_libsecp256k1_is_available(self): def test_libsecp256k1_is_available(self):
# we want the unit testing framework to test with libsecp256k1 available. # we want the unit testing framework to test with libsecp256k1 available.
self.assertTrue(bool(ecc_fast._libsecp256k1)) self.assertTrue(bool(ecc._libsecp256k1))
def test_pycryptodomex_is_available(self): def test_pycryptodomex_is_available(self):
# we want the unit testing framework to test with pycryptodomex available. # we want the unit testing framework to test with pycryptodomex available.

3
tests/test_descriptor.py

@ -8,6 +8,8 @@
from binascii import unhexlify from binascii import unhexlify
import unittest import unittest
import electrum_ecc as ecc
from electrum.descriptor import ( from electrum.descriptor import (
parse_descriptor, parse_descriptor,
MultisigDescriptor, MultisigDescriptor,
@ -18,7 +20,6 @@ from electrum.descriptor import (
WSHDescriptor, WSHDescriptor,
PubkeyProvider, PubkeyProvider,
) )
from electrum import ecc
from electrum.util import bfh from electrum.util import bfh
from . import ElectrumTestCase, as_testnet from . import ElectrumTestCase, as_testnet

8
tests/test_ecc.py

@ -4,9 +4,11 @@ from ctypes import (
) )
import io import io
from electrum import ecc, bitcoin import electrum_ecc as ecc
from electrum.ecc import ECPubkey, ECPrivkey from electrum_ecc import ECPubkey, ECPrivkey
from electrum.ecc_fast import _libsecp256k1 from electrum_ecc import _libsecp256k1
from electrum import bitcoin
from electrum import crypto from electrum import crypto
from electrum.crypto import sha256 from electrum.crypto import sha256

2
tests/test_lnpeer.py

@ -13,6 +13,7 @@ import unittest
from typing import Iterable, NamedTuple, Tuple, List, Dict from typing import Iterable, NamedTuple, Tuple, List, Dict
from aiorpcx import timeout_after, TaskTimeout from aiorpcx import timeout_after, TaskTimeout
from electrum_ecc import ECPrivkey
import electrum import electrum
import electrum.trampoline import electrum.trampoline
@ -20,7 +21,6 @@ from electrum import bitcoin
from electrum import util from electrum import util
from electrum import constants from electrum import constants
from electrum.network import Network from electrum.network import Network
from electrum.ecc import ECPrivkey
from electrum import simple_config, lnutil from electrum import simple_config, lnutil
from electrum.lnaddr import lnencode, LnAddr, lndecode from electrum.lnaddr import lnencode, LnAddr, lndecode
from electrum.bitcoin import COIN, sha256 from electrum.bitcoin import COIN, sha256

3
tests/test_lntransport.py

@ -1,7 +1,8 @@
import asyncio import asyncio
from electrum_ecc import ECPrivkey
from electrum import util from electrum import util
from electrum.ecc import ECPrivkey
from electrum.lnutil import LNPeerAddr from electrum.lnutil import LNPeerAddr
from electrum.lntransport import LNResponderTransport, LNTransport from electrum.lntransport import LNResponderTransport, LNTransport
from electrum.util import OldTaskGroup from electrum.util import OldTaskGroup

3
tests/test_lnutil.py

@ -1,8 +1,9 @@
import unittest import unittest
import json import json
import electrum_ecc as ecc
from electrum import bitcoin from electrum import bitcoin
from electrum import ecc
from electrum.json_db import StoredDict from electrum.json_db import StoredDict
from electrum.lnutil import (RevocationStore, get_per_commitment_secret_from_seed, make_offered_htlc, from electrum.lnutil import (RevocationStore, get_per_commitment_secret_from_seed, make_offered_htlc,
make_received_htlc, make_commitment, make_htlc_tx_witness, make_htlc_tx_output, make_received_htlc, make_commitment, make_htlc_tx_witness, make_htlc_tx_output,

3
tests/test_transaction.py

@ -2,6 +2,8 @@ import json
import os import os
from typing import NamedTuple, Union from typing import NamedTuple, Union
from electrum_ecc import ECPrivkey
from electrum import transaction, bitcoin from electrum import transaction, bitcoin
from electrum.transaction import (convert_raw_tx_to_hex, tx_from_any, Transaction, from electrum.transaction import (convert_raw_tx_to_hex, tx_from_any, Transaction,
PartialTransaction, TxOutpoint, PartialTxInput, PartialTransaction, TxOutpoint, PartialTxInput,
@ -10,7 +12,6 @@ from electrum.transaction import (convert_raw_tx_to_hex, tx_from_any, Transactio
from electrum.util import bfh from electrum.util import bfh
from electrum.bitcoin import (deserialize_privkey, opcodes, from electrum.bitcoin import (deserialize_privkey, opcodes,
construct_script, construct_witness) construct_script, construct_witness)
from electrum.ecc import ECPrivkey
from electrum import descriptor from electrum import descriptor
from .test_bitcoin import disable_ecdsa_r_value_grinding from .test_bitcoin import disable_ecdsa_r_value_grinding

Loading…
Cancel
Save