mirror of
https://github.com/LBRYFoundation/LBRY-Vault.git
synced 2025-08-27 07:23:25 +00:00
Merge pull request #6014 from SomberNight/20200304_pycryptodomex
add 'cryptography' as optional dependency; clean README and sdist
This commit is contained in:
commit
dbd77b7d8e
15 changed files with 259 additions and 82 deletions
|
@ -30,7 +30,7 @@ jobs:
|
||||||
- sudo apt-get -qq update
|
- sudo apt-get -qq update
|
||||||
- sudo apt-get install -yq bitcoind
|
- sudo apt-get install -yq bitcoind
|
||||||
- sudo apt-get -y install libsecp256k1-0
|
- sudo apt-get -y install libsecp256k1-0
|
||||||
- pip install -r contrib/requirements/requirements.txt
|
- pip install .[tests]
|
||||||
- pip install electrumx
|
- pip install electrumx
|
||||||
before_script:
|
before_script:
|
||||||
- electrum/tests/regtest/start_bitcoind.sh
|
- electrum/tests/regtest/start_bitcoind.sh
|
||||||
|
|
41
README.rst
41
README.rst
|
@ -26,16 +26,26 @@ Electrum - Lightweight Bitcoin client
|
||||||
Getting started
|
Getting started
|
||||||
===============
|
===============
|
||||||
|
|
||||||
Electrum itself is pure Python, and so are most of the required dependencies.
|
(*If you've come here looking to simply run Electrum,* `you may download it here`_.)
|
||||||
|
|
||||||
Non-python dependencies
|
.. _you may download it here: https://electrum.org/#download
|
||||||
-----------------------
|
|
||||||
|
Electrum itself is pure Python, and so are most of the required dependencies,
|
||||||
|
but not everything. The following sections describe how to run from source, but here
|
||||||
|
is a TL;DR::
|
||||||
|
|
||||||
|
sudo apt-get install libsecp256k1-0
|
||||||
|
python3 -m pip install --user .[gui,crypto]
|
||||||
|
|
||||||
|
|
||||||
|
Not pure-python dependencies
|
||||||
|
----------------------------
|
||||||
|
|
||||||
If you want to use the Qt interface, install the Qt dependencies::
|
If you want to use the Qt interface, install the Qt dependencies::
|
||||||
|
|
||||||
sudo apt-get install python3-pyqt5
|
sudo apt-get install python3-pyqt5
|
||||||
|
|
||||||
For elliptic curve operations, libsecp256k1 is a required dependency::
|
For elliptic curve operations, `libsecp256k1`_ is a required dependency::
|
||||||
|
|
||||||
sudo apt-get install libsecp256k1-0
|
sudo apt-get install libsecp256k1-0
|
||||||
|
|
||||||
|
@ -44,13 +54,26 @@ libsecp256k1 yourself::
|
||||||
|
|
||||||
./contrib/make_libsecp256k1.sh
|
./contrib/make_libsecp256k1.sh
|
||||||
|
|
||||||
|
Due to the need for fast symmetric ciphers, either one of `pycryptodomex`_
|
||||||
|
or `cryptography`_ is required. Install from your package manager
|
||||||
|
(or from pip)::
|
||||||
|
|
||||||
|
sudo apt-get install python3-cryptography
|
||||||
|
|
||||||
|
|
||||||
|
If you would like hardware wallet support, see `this`_.
|
||||||
|
|
||||||
|
.. _libsecp256k1: https://github.com/bitcoin-core/secp256k1
|
||||||
|
.. _pycryptodomex: https://github.com/Legrandin/pycryptodome
|
||||||
|
.. _cryptography: https://github.com/pyca/cryptography
|
||||||
|
.. _this: https://github.com/spesmilo/electrum-docs/blob/master/hardware-linux.rst
|
||||||
|
|
||||||
Running from tar.gz
|
Running from tar.gz
|
||||||
-------------------
|
-------------------
|
||||||
|
|
||||||
If you downloaded the official package (tar.gz), you can run
|
If you downloaded the official package (tar.gz), you can run
|
||||||
Electrum from its root directory without installing it on your
|
Electrum from its root directory without installing it on your
|
||||||
system; all the python dependencies are included in the 'packages'
|
system; all the pure python dependencies are included in the 'packages'
|
||||||
directory. To run Electrum from its root directory, just do::
|
directory. To run Electrum from its root directory, just do::
|
||||||
|
|
||||||
./run_electrum
|
./run_electrum
|
||||||
|
@ -63,13 +86,9 @@ You can also install Electrum on your system, by running this command::
|
||||||
This will download and install the Python dependencies used by
|
This will download and install the Python dependencies used by
|
||||||
Electrum instead of using the 'packages' directory.
|
Electrum instead of using the 'packages' directory.
|
||||||
|
|
||||||
If you cloned the git repository, you need to compile extra files
|
|
||||||
before you can run Electrum. Read the next section, "Development
|
|
||||||
version".
|
|
||||||
|
|
||||||
|
Development version (git clone)
|
||||||
Development version
|
-------------------------------
|
||||||
-------------------
|
|
||||||
|
|
||||||
Check out the code from GitHub::
|
Check out the code from GitHub::
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,39 @@
|
||||||
pip==19.3.1 \
|
pip==19.3.1 \
|
||||||
--hash=sha256:21207d76c1031e517668898a6b46a9fb1501c7a4710ef5dfd6a40ad9e6757ea7 \
|
--hash=sha256:21207d76c1031e517668898a6b46a9fb1501c7a4710ef5dfd6a40ad9e6757ea7 \
|
||||||
--hash=sha256:6917c65fc3769ecdc61405d3dfd97afdedd75808d200b2838d7d961cebc0c2c7
|
--hash=sha256:6917c65fc3769ecdc61405d3dfd97afdedd75808d200b2838d7d961cebc0c2c7
|
||||||
|
pycryptodomex==3.9.4 \
|
||||||
|
--hash=sha256:0943b65fb41b7403a9def6214061fdd9ab9afd0bbc581e553c72eebe60bded36 \
|
||||||
|
--hash=sha256:0a1dbb5c4d975a4ea568fb7686550aa225d94023191fb0cca8747dc5b5d77857 \
|
||||||
|
--hash=sha256:0f43f1608518347fdcb9c8f443fa5cabedd33f94188b13e4196a3a7ba90d169c \
|
||||||
|
--hash=sha256:11ce5fec5990e34e3981ed14897ba601c83957b577d77d395f1f8f878a179f98 \
|
||||||
|
--hash=sha256:17a09e38fdc91e4857cf5a7ce82f3c0b229c3977490f2146513e366923fc256b \
|
||||||
|
--hash=sha256:22d970cee5c096b9123415e183ae03702b2cd4d3ba3f0ced25c4e1aba3967167 \
|
||||||
|
--hash=sha256:2a1793efcbae3a2264c5e0e492a2629eb10d895d6e5f17dbbd00eb8b489c6bda \
|
||||||
|
--hash=sha256:30a8a148a0fe482cec1aaf942bbd0ade56ec197c14fe058b2a94318c57e1f991 \
|
||||||
|
--hash=sha256:32fbbaf964c5184d3f3e349085b0536dd28184b02e2b014fc900f58bbc126339 \
|
||||||
|
--hash=sha256:347d67faee36d449dc9632da411cc318df52959079062627f1243001b10dc227 \
|
||||||
|
--hash=sha256:45f4b4e5461a041518baabc52340c249b60833aa84cea6377dc8016a2b33c666 \
|
||||||
|
--hash=sha256:4717daec0035034b002d31c42e55431c970e3e38a78211f43990e1b7eaf19e28 \
|
||||||
|
--hash=sha256:51a1ac9e7dda81da444fed8be558a60ec88dfc73b2aa4b0efa310e87acb75838 \
|
||||||
|
--hash=sha256:53e9dcc8f14783f6300b70da325a50ac1b0a3dbaee323bd9dc3f71d409c197a1 \
|
||||||
|
--hash=sha256:5519a2ed776e193688b7ddb61ab709303f6eb7d1237081e298283c72acc44271 \
|
||||||
|
--hash=sha256:583450e8e80a0885c453211ed2bd69ceea634d8c904f23ff8687f677fe810e95 \
|
||||||
|
--hash=sha256:60f862bd2a07133585a4fc2ce2b1a8ec24746b07ac44307d22ef2b767cb03435 \
|
||||||
|
--hash=sha256:612091f1d3c84e723bec7cb855cf77576e646045744794c9a3f75ba80737762f \
|
||||||
|
--hash=sha256:629a87b87c8203b8789ccefc7f2f2faecd2daaeb56bdd0b4e44cd89565f2db07 \
|
||||||
|
--hash=sha256:6e56ec4c8938fb388b6f250ddd5e21c15e8f25a76e0ad0e2abae9afee09e67b4 \
|
||||||
|
--hash=sha256:8e8092651844a11ec7fa534395f3dfe99256ce4edca06f128efc9d770d6e1dc1 \
|
||||||
|
--hash=sha256:8f5f260629876603e08f3ce95c8ccd9b6b83bf9a921c41409046796267f7adc5 \
|
||||||
|
--hash=sha256:9a6b74f38613f54c56bd759b411a352258f47489bbefd1d57c930a291498b35b \
|
||||||
|
--hash=sha256:a5a13ebb52c4cd065fb673d8c94f39f30823428a4de19e1f3f828b63a8882d1e \
|
||||||
|
--hash=sha256:a77ca778a476829876a3a70ae880073379160e4a465d057e3c4e1c79acdf1b8a \
|
||||||
|
--hash=sha256:a9f7be3d19f79429c2118fd61bc2ec4fa095e93b56fb3a5f3009822402c4380f \
|
||||||
|
--hash=sha256:dc15a467c4f9e4b43748ba2f97aea66f67812bfd581818284c47cadc81d4caec \
|
||||||
|
--hash=sha256:e13cdeea23059f7577c230fd580d2c8178e67ebe10e360041abe86c33c316f1c \
|
||||||
|
--hash=sha256:e45b85c8521bca6bdfaf57e4987743ade53e9f03529dd3adbc9524094c6d55c4 \
|
||||||
|
--hash=sha256:e87f17867b260f57c88487f943eb4d46c90532652bb37046e764842c3b66cbb1 \
|
||||||
|
--hash=sha256:ee40a5b156f6c1192bc3082e9d73d0479904433cdda83110546cd67f5a15a5be \
|
||||||
|
--hash=sha256:ef63ffde3b267043579af8830fc97fc3b9b8a526a24e3ba23af9989d4e9e689a
|
||||||
PyQt5==5.11.3 \
|
PyQt5==5.11.3 \
|
||||||
--hash=sha256:517e4339135c4874b799af0d484bc2e8c27b54850113a68eec40a0b56534f450 \
|
--hash=sha256:517e4339135c4874b799af0d484bc2e8c27b54850113a68eec40a0b56534f450 \
|
||||||
--hash=sha256:ac1eb5a114b6e7788e8be378be41c5e54b17d5158994504e85e43b5fca006a39 \
|
--hash=sha256:ac1eb5a114b6e7788e8be378be41c5e54b17d5158994504e85e43b5fca006a39 \
|
||||||
|
|
|
@ -103,39 +103,6 @@ protobuf==3.11.1 \
|
||||||
--hash=sha256:e88a924b591b06d0191620e9c8aa75297b3111066bb09d49a24bae1054a10c13
|
--hash=sha256:e88a924b591b06d0191620e9c8aa75297b3111066bb09d49a24bae1054a10c13
|
||||||
pyaes==1.6.1 \
|
pyaes==1.6.1 \
|
||||||
--hash=sha256:02c1b1405c38d3c370b085fb952dd8bea3fadcee6411ad99f312cc129c536d8f
|
--hash=sha256:02c1b1405c38d3c370b085fb952dd8bea3fadcee6411ad99f312cc129c536d8f
|
||||||
pycryptodomex==3.9.4 \
|
|
||||||
--hash=sha256:0943b65fb41b7403a9def6214061fdd9ab9afd0bbc581e553c72eebe60bded36 \
|
|
||||||
--hash=sha256:0a1dbb5c4d975a4ea568fb7686550aa225d94023191fb0cca8747dc5b5d77857 \
|
|
||||||
--hash=sha256:0f43f1608518347fdcb9c8f443fa5cabedd33f94188b13e4196a3a7ba90d169c \
|
|
||||||
--hash=sha256:11ce5fec5990e34e3981ed14897ba601c83957b577d77d395f1f8f878a179f98 \
|
|
||||||
--hash=sha256:17a09e38fdc91e4857cf5a7ce82f3c0b229c3977490f2146513e366923fc256b \
|
|
||||||
--hash=sha256:22d970cee5c096b9123415e183ae03702b2cd4d3ba3f0ced25c4e1aba3967167 \
|
|
||||||
--hash=sha256:2a1793efcbae3a2264c5e0e492a2629eb10d895d6e5f17dbbd00eb8b489c6bda \
|
|
||||||
--hash=sha256:30a8a148a0fe482cec1aaf942bbd0ade56ec197c14fe058b2a94318c57e1f991 \
|
|
||||||
--hash=sha256:32fbbaf964c5184d3f3e349085b0536dd28184b02e2b014fc900f58bbc126339 \
|
|
||||||
--hash=sha256:347d67faee36d449dc9632da411cc318df52959079062627f1243001b10dc227 \
|
|
||||||
--hash=sha256:45f4b4e5461a041518baabc52340c249b60833aa84cea6377dc8016a2b33c666 \
|
|
||||||
--hash=sha256:4717daec0035034b002d31c42e55431c970e3e38a78211f43990e1b7eaf19e28 \
|
|
||||||
--hash=sha256:51a1ac9e7dda81da444fed8be558a60ec88dfc73b2aa4b0efa310e87acb75838 \
|
|
||||||
--hash=sha256:53e9dcc8f14783f6300b70da325a50ac1b0a3dbaee323bd9dc3f71d409c197a1 \
|
|
||||||
--hash=sha256:5519a2ed776e193688b7ddb61ab709303f6eb7d1237081e298283c72acc44271 \
|
|
||||||
--hash=sha256:583450e8e80a0885c453211ed2bd69ceea634d8c904f23ff8687f677fe810e95 \
|
|
||||||
--hash=sha256:60f862bd2a07133585a4fc2ce2b1a8ec24746b07ac44307d22ef2b767cb03435 \
|
|
||||||
--hash=sha256:612091f1d3c84e723bec7cb855cf77576e646045744794c9a3f75ba80737762f \
|
|
||||||
--hash=sha256:629a87b87c8203b8789ccefc7f2f2faecd2daaeb56bdd0b4e44cd89565f2db07 \
|
|
||||||
--hash=sha256:6e56ec4c8938fb388b6f250ddd5e21c15e8f25a76e0ad0e2abae9afee09e67b4 \
|
|
||||||
--hash=sha256:8e8092651844a11ec7fa534395f3dfe99256ce4edca06f128efc9d770d6e1dc1 \
|
|
||||||
--hash=sha256:8f5f260629876603e08f3ce95c8ccd9b6b83bf9a921c41409046796267f7adc5 \
|
|
||||||
--hash=sha256:9a6b74f38613f54c56bd759b411a352258f47489bbefd1d57c930a291498b35b \
|
|
||||||
--hash=sha256:a5a13ebb52c4cd065fb673d8c94f39f30823428a4de19e1f3f828b63a8882d1e \
|
|
||||||
--hash=sha256:a77ca778a476829876a3a70ae880073379160e4a465d057e3c4e1c79acdf1b8a \
|
|
||||||
--hash=sha256:a9f7be3d19f79429c2118fd61bc2ec4fa095e93b56fb3a5f3009822402c4380f \
|
|
||||||
--hash=sha256:dc15a467c4f9e4b43748ba2f97aea66f67812bfd581818284c47cadc81d4caec \
|
|
||||||
--hash=sha256:e13cdeea23059f7577c230fd580d2c8178e67ebe10e360041abe86c33c316f1c \
|
|
||||||
--hash=sha256:e45b85c8521bca6bdfaf57e4987743ade53e9f03529dd3adbc9524094c6d55c4 \
|
|
||||||
--hash=sha256:e87f17867b260f57c88487f943eb4d46c90532652bb37046e764842c3b66cbb1 \
|
|
||||||
--hash=sha256:ee40a5b156f6c1192bc3082e9d73d0479904433cdda83110546cd67f5a15a5be \
|
|
||||||
--hash=sha256:ef63ffde3b267043579af8830fc97fc3b9b8a526a24e3ba23af9989d4e9e689a
|
|
||||||
pyrsistent==0.15.6 \
|
pyrsistent==0.15.6 \
|
||||||
--hash=sha256:f3b280d030afb652f79d67c5586157c5c1355c9a58dfc7940566e28d28f3df1b
|
--hash=sha256:f3b280d030afb652f79d67c5586157c5c1355c9a58dfc7940566e28d28f3df1b
|
||||||
QDarkStyle==2.6.8 \
|
QDarkStyle==2.6.8 \
|
||||||
|
|
|
@ -1,2 +1,3 @@
|
||||||
PyQt5<5.12
|
PyQt5<5.12
|
||||||
PyQt5-sip<=4.19.13
|
PyQt5-sip<=4.19.13
|
||||||
|
pycryptodomex>=3.7
|
||||||
|
|
|
@ -9,7 +9,6 @@ aiohttp>=3.3.0,<4.0.0
|
||||||
aiohttp_socks
|
aiohttp_socks
|
||||||
certifi
|
certifi
|
||||||
bitstring
|
bitstring
|
||||||
pycryptodomex>=3.7
|
|
||||||
jsonrpcserver
|
jsonrpcserver
|
||||||
jsonrpcclient
|
jsonrpcclient
|
||||||
attrs
|
attrs
|
||||||
|
|
|
@ -25,6 +25,7 @@
|
||||||
|
|
||||||
import base64
|
import base64
|
||||||
import os
|
import os
|
||||||
|
import sys
|
||||||
import hashlib
|
import hashlib
|
||||||
import hmac
|
import hmac
|
||||||
from typing import Union
|
from typing import Union
|
||||||
|
@ -35,10 +36,33 @@ from .util import assert_bytes, InvalidPassword, to_bytes, to_string, WalletFile
|
||||||
from .i18n import _
|
from .i18n import _
|
||||||
|
|
||||||
|
|
||||||
|
HAS_CRYPTODOME = False
|
||||||
try:
|
try:
|
||||||
from Cryptodome.Cipher import AES
|
from Cryptodome.Cipher import ChaCha20_Poly1305 as CD_ChaCha20_Poly1305
|
||||||
|
from Cryptodome.Cipher import ChaCha20 as CD_ChaCha20
|
||||||
|
from Cryptodome.Cipher import AES as CD_AES
|
||||||
except:
|
except:
|
||||||
AES = None
|
pass
|
||||||
|
else:
|
||||||
|
HAS_CRYPTODOME = True
|
||||||
|
|
||||||
|
HAS_CRYPTOGRAPHY = False
|
||||||
|
try:
|
||||||
|
import cryptography
|
||||||
|
from cryptography import exceptions
|
||||||
|
from cryptography.hazmat.primitives.ciphers import Cipher as CG_Cipher
|
||||||
|
from cryptography.hazmat.primitives.ciphers import algorithms as CG_algorithms
|
||||||
|
from cryptography.hazmat.primitives.ciphers import modes as CG_modes
|
||||||
|
from cryptography.hazmat.backends import default_backend as CG_default_backend
|
||||||
|
import cryptography.hazmat.primitives.ciphers.aead as CG_aead
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
else:
|
||||||
|
HAS_CRYPTOGRAPHY = True
|
||||||
|
|
||||||
|
|
||||||
|
if not (HAS_CRYPTODOME or HAS_CRYPTOGRAPHY):
|
||||||
|
sys.exit(f"Error: at least one of ('pycryptodomex', 'cryptography') needs to be installed.")
|
||||||
|
|
||||||
|
|
||||||
class InvalidPadding(Exception):
|
class InvalidPadding(Exception):
|
||||||
|
@ -67,8 +91,12 @@ def strip_PKCS7_padding(data: bytes) -> bytes:
|
||||||
def aes_encrypt_with_iv(key: bytes, iv: bytes, data: bytes) -> bytes:
|
def aes_encrypt_with_iv(key: bytes, iv: bytes, data: bytes) -> bytes:
|
||||||
assert_bytes(key, iv, data)
|
assert_bytes(key, iv, data)
|
||||||
data = append_PKCS7_padding(data)
|
data = append_PKCS7_padding(data)
|
||||||
if AES:
|
if HAS_CRYPTODOME:
|
||||||
e = AES.new(key, AES.MODE_CBC, iv).encrypt(data)
|
e = CD_AES.new(key, CD_AES.MODE_CBC, iv).encrypt(data)
|
||||||
|
elif HAS_CRYPTOGRAPHY:
|
||||||
|
cipher = CG_Cipher(CG_algorithms.AES(key), CG_modes.CBC(iv), backend=CG_default_backend())
|
||||||
|
encryptor = cipher.encryptor()
|
||||||
|
e = encryptor.update(data) + encryptor.finalize()
|
||||||
else:
|
else:
|
||||||
aes_cbc = pyaes.AESModeOfOperationCBC(key, iv=iv)
|
aes_cbc = pyaes.AESModeOfOperationCBC(key, iv=iv)
|
||||||
aes = pyaes.Encrypter(aes_cbc, padding=pyaes.PADDING_NONE)
|
aes = pyaes.Encrypter(aes_cbc, padding=pyaes.PADDING_NONE)
|
||||||
|
@ -78,9 +106,13 @@ def aes_encrypt_with_iv(key: bytes, iv: bytes, data: bytes) -> bytes:
|
||||||
|
|
||||||
def aes_decrypt_with_iv(key: bytes, iv: bytes, data: bytes) -> bytes:
|
def aes_decrypt_with_iv(key: bytes, iv: bytes, data: bytes) -> bytes:
|
||||||
assert_bytes(key, iv, data)
|
assert_bytes(key, iv, data)
|
||||||
if AES:
|
if HAS_CRYPTODOME:
|
||||||
cipher = AES.new(key, AES.MODE_CBC, iv)
|
cipher = CD_AES.new(key, CD_AES.MODE_CBC, iv)
|
||||||
data = cipher.decrypt(data)
|
data = cipher.decrypt(data)
|
||||||
|
elif HAS_CRYPTOGRAPHY:
|
||||||
|
cipher = CG_Cipher(CG_algorithms.AES(key), CG_modes.CBC(iv), backend=CG_default_backend())
|
||||||
|
decryptor = cipher.decryptor()
|
||||||
|
data = decryptor.update(data) + decryptor.finalize()
|
||||||
else:
|
else:
|
||||||
aes_cbc = pyaes.AESModeOfOperationCBC(key, iv=iv)
|
aes_cbc = pyaes.AESModeOfOperationCBC(key, iv=iv)
|
||||||
aes = pyaes.Decrypter(aes_cbc, padding=pyaes.PADDING_NONE)
|
aes = pyaes.Decrypter(aes_cbc, padding=pyaes.PADDING_NONE)
|
||||||
|
@ -216,3 +248,55 @@ def hmac_oneshot(key: bytes, msg: bytes, digest) -> bytes:
|
||||||
return hmac.digest(key, msg, digest)
|
return hmac.digest(key, msg, digest)
|
||||||
else:
|
else:
|
||||||
return hmac.new(key, msg, digest).digest()
|
return hmac.new(key, msg, digest).digest()
|
||||||
|
|
||||||
|
|
||||||
|
def chacha20_poly1305_encrypt(*, key: bytes, nonce: bytes, associated_data: bytes, data: bytes) -> bytes:
|
||||||
|
assert isinstance(key, (bytes, bytearray))
|
||||||
|
assert isinstance(nonce, (bytes, bytearray))
|
||||||
|
assert isinstance(associated_data, (bytes, bytearray))
|
||||||
|
assert isinstance(data, (bytes, bytearray))
|
||||||
|
if HAS_CRYPTODOME:
|
||||||
|
cipher = CD_ChaCha20_Poly1305.new(key=key, nonce=nonce)
|
||||||
|
cipher.update(associated_data)
|
||||||
|
ciphertext, mac = cipher.encrypt_and_digest(plaintext=data)
|
||||||
|
return ciphertext + mac
|
||||||
|
if HAS_CRYPTOGRAPHY:
|
||||||
|
a = CG_aead.ChaCha20Poly1305(key)
|
||||||
|
return a.encrypt(nonce, data, associated_data)
|
||||||
|
raise Exception("no chacha20 backed found")
|
||||||
|
|
||||||
|
|
||||||
|
def chacha20_poly1305_decrypt(*, key: bytes, nonce: bytes, associated_data: bytes, data: bytes) -> bytes:
|
||||||
|
assert isinstance(key, (bytes, bytearray))
|
||||||
|
assert isinstance(nonce, (bytes, bytearray))
|
||||||
|
assert isinstance(associated_data, (bytes, bytearray))
|
||||||
|
assert isinstance(data, (bytes, bytearray))
|
||||||
|
if HAS_CRYPTODOME:
|
||||||
|
cipher = CD_ChaCha20_Poly1305.new(key=key, nonce=nonce)
|
||||||
|
cipher.update(associated_data)
|
||||||
|
# raises ValueError if not valid (e.g. incorrect MAC)
|
||||||
|
return cipher.decrypt_and_verify(ciphertext=data[:-16], received_mac_tag=data[-16:])
|
||||||
|
if HAS_CRYPTOGRAPHY:
|
||||||
|
a = CG_aead.ChaCha20Poly1305(key)
|
||||||
|
try:
|
||||||
|
return a.decrypt(nonce, data, associated_data)
|
||||||
|
except cryptography.exceptions.InvalidTag as e:
|
||||||
|
raise ValueError("invalid tag") from e
|
||||||
|
raise Exception("no chacha20 backed found")
|
||||||
|
|
||||||
|
|
||||||
|
def chacha20_encrypt(*, key: bytes, nonce: bytes, data: bytes) -> bytes:
|
||||||
|
assert isinstance(key, (bytes, bytearray))
|
||||||
|
assert isinstance(nonce, (bytes, bytearray))
|
||||||
|
assert isinstance(data, (bytes, bytearray))
|
||||||
|
assert len(nonce) == 8, f"unexpected nonce size: {len(nonce)} (expected: 8)"
|
||||||
|
if HAS_CRYPTODOME:
|
||||||
|
cipher = CD_ChaCha20.new(key=key, nonce=nonce)
|
||||||
|
return cipher.encrypt(data)
|
||||||
|
if HAS_CRYPTOGRAPHY:
|
||||||
|
nonce = bytes(8) + nonce # cryptography wants 16 byte nonces
|
||||||
|
algo = CG_algorithms.ChaCha20(key=key, nonce=nonce)
|
||||||
|
cipher = CG_Cipher(algo, mode=None, backend=CG_default_backend())
|
||||||
|
encryptor = cipher.encryptor()
|
||||||
|
return encryptor.update(data)
|
||||||
|
raise Exception("no chacha20 backed found")
|
||||||
|
|
|
@ -27,10 +27,8 @@ import hashlib
|
||||||
from typing import Sequence, List, Tuple, NamedTuple, TYPE_CHECKING
|
from typing import Sequence, List, Tuple, NamedTuple, TYPE_CHECKING
|
||||||
from enum import IntEnum, IntFlag
|
from enum import IntEnum, IntFlag
|
||||||
|
|
||||||
from Cryptodome.Cipher import ChaCha20
|
|
||||||
|
|
||||||
from . import ecc
|
from . import ecc
|
||||||
from .crypto import sha256, hmac_oneshot
|
from .crypto import sha256, hmac_oneshot, chacha20_encrypt
|
||||||
from .util import bh2u, profiler, xor_bytes, bfh
|
from .util import bh2u, 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,
|
||||||
NUM_MAX_EDGES_IN_PAYMENT_PATH, ShortChannelID)
|
NUM_MAX_EDGES_IN_PAYMENT_PATH, ShortChannelID)
|
||||||
|
@ -227,8 +225,9 @@ def generate_filler(key_type: bytes, num_hops: int, hop_size: int,
|
||||||
|
|
||||||
|
|
||||||
def generate_cipher_stream(stream_key: bytes, num_bytes: int) -> bytes:
|
def generate_cipher_stream(stream_key: bytes, num_bytes: int) -> bytes:
|
||||||
cipher = ChaCha20.new(key=stream_key, nonce=bytes(8))
|
return chacha20_encrypt(key=stream_key,
|
||||||
return cipher.encrypt(bytes(num_bytes))
|
nonce=bytes(8),
|
||||||
|
data=bytes(num_bytes))
|
||||||
|
|
||||||
|
|
||||||
class ProcessedOnionPacket(NamedTuple):
|
class ProcessedOnionPacket(NamedTuple):
|
||||||
|
|
|
@ -9,9 +9,7 @@ import hashlib
|
||||||
import asyncio
|
import asyncio
|
||||||
from asyncio import StreamReader, StreamWriter
|
from asyncio import StreamReader, StreamWriter
|
||||||
|
|
||||||
from Cryptodome.Cipher import ChaCha20_Poly1305
|
from .crypto import sha256, hmac_oneshot, chacha20_poly1305_encrypt, chacha20_poly1305_decrypt
|
||||||
|
|
||||||
from .crypto import sha256, hmac_oneshot
|
|
||||||
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 . import ecc
|
||||||
|
@ -41,17 +39,17 @@ def get_nonce_bytes(n):
|
||||||
|
|
||||||
def aead_encrypt(key: bytes, nonce: int, associated_data: bytes, data: bytes) -> bytes:
|
def aead_encrypt(key: bytes, nonce: int, associated_data: bytes, data: bytes) -> bytes:
|
||||||
nonce_bytes = get_nonce_bytes(nonce)
|
nonce_bytes = get_nonce_bytes(nonce)
|
||||||
cipher = ChaCha20_Poly1305.new(key=key, nonce=nonce_bytes)
|
return chacha20_poly1305_encrypt(key=key,
|
||||||
cipher.update(associated_data)
|
nonce=nonce_bytes,
|
||||||
ciphertext, mac = cipher.encrypt_and_digest(plaintext=data)
|
associated_data=associated_data,
|
||||||
return ciphertext + mac
|
data=data)
|
||||||
|
|
||||||
def aead_decrypt(key: bytes, nonce: int, associated_data: bytes, data: bytes) -> bytes:
|
def aead_decrypt(key: bytes, nonce: int, associated_data: bytes, data: bytes) -> bytes:
|
||||||
nonce_bytes = get_nonce_bytes(nonce)
|
nonce_bytes = get_nonce_bytes(nonce)
|
||||||
cipher = ChaCha20_Poly1305.new(key=key, nonce=nonce_bytes)
|
return chacha20_poly1305_decrypt(key=key,
|
||||||
cipher.update(associated_data)
|
nonce=nonce_bytes,
|
||||||
# raises ValueError if not valid (e.g. incorrect MAC)
|
associated_data=associated_data,
|
||||||
return cipher.decrypt_and_verify(ciphertext=data[:-16], received_mac_tag=data[-16:])
|
data=data)
|
||||||
|
|
||||||
def get_bolt8_hkdf(salt, ikm):
|
def get_bolt8_hkdf(salt, ikm):
|
||||||
"""RFC5869 HKDF instantiated in the specific form
|
"""RFC5869 HKDF instantiated in the specific form
|
||||||
|
|
|
@ -34,8 +34,8 @@ except ImportError:
|
||||||
|
|
||||||
|
|
||||||
def needs_test_with_all_aes_implementations(func):
|
def needs_test_with_all_aes_implementations(func):
|
||||||
"""Function decorator to run a unit test twice:
|
"""Function decorator to run a unit test multiple times:
|
||||||
once when pycryptodomex is not available, once when it is.
|
once with each AES implementation.
|
||||||
|
|
||||||
NOTE: this is inherently sequential;
|
NOTE: this is inherently sequential;
|
||||||
tests running in parallel would break things
|
tests running in parallel would break things
|
||||||
|
@ -44,18 +44,46 @@ def needs_test_with_all_aes_implementations(func):
|
||||||
if FAST_TESTS: # if set, only run tests once, using fastest implementation
|
if FAST_TESTS: # if set, only run tests once, using fastest implementation
|
||||||
func(*args, **kwargs)
|
func(*args, **kwargs)
|
||||||
return
|
return
|
||||||
_aes = crypto.AES
|
has_cryptodome = crypto.HAS_CRYPTODOME
|
||||||
crypto.AES = None
|
has_cryptography = crypto.HAS_CRYPTOGRAPHY
|
||||||
try:
|
try:
|
||||||
# first test without pycryptodomex
|
(crypto.HAS_CRYPTODOME, crypto.HAS_CRYPTOGRAPHY) = False, False
|
||||||
func(*args, **kwargs)
|
func(*args, **kwargs) # pyaes
|
||||||
|
if has_cryptodome:
|
||||||
|
(crypto.HAS_CRYPTODOME, crypto.HAS_CRYPTOGRAPHY) = True, False
|
||||||
|
func(*args, **kwargs) # cryptodome
|
||||||
|
if has_cryptography:
|
||||||
|
(crypto.HAS_CRYPTODOME, crypto.HAS_CRYPTOGRAPHY) = False, True
|
||||||
|
func(*args, **kwargs) # cryptography
|
||||||
finally:
|
finally:
|
||||||
crypto.AES = _aes
|
crypto.HAS_CRYPTODOME = has_cryptodome
|
||||||
# if pycryptodomex is not available, we are done
|
crypto.HAS_CRYPTOGRAPHY = has_cryptography
|
||||||
if not _aes:
|
return run_test
|
||||||
return
|
|
||||||
# if pycryptodomex is available, test again now
|
|
||||||
|
def needs_test_with_all_chacha20_implementations(func):
|
||||||
|
"""Function decorator to run a unit test multiple times:
|
||||||
|
once with each ChaCha20/Poly1305 implementation.
|
||||||
|
|
||||||
|
NOTE: this is inherently sequential;
|
||||||
|
tests running in parallel would break things
|
||||||
|
"""
|
||||||
|
def run_test(*args, **kwargs):
|
||||||
|
if FAST_TESTS: # if set, only run tests once, using fastest implementation
|
||||||
func(*args, **kwargs)
|
func(*args, **kwargs)
|
||||||
|
return
|
||||||
|
has_cryptodome = crypto.HAS_CRYPTODOME
|
||||||
|
has_cryptography = crypto.HAS_CRYPTOGRAPHY
|
||||||
|
try:
|
||||||
|
if has_cryptodome:
|
||||||
|
(crypto.HAS_CRYPTODOME, crypto.HAS_CRYPTOGRAPHY) = True, False
|
||||||
|
func(*args, **kwargs) # cryptodome
|
||||||
|
if has_cryptography:
|
||||||
|
(crypto.HAS_CRYPTODOME, crypto.HAS_CRYPTOGRAPHY) = False, True
|
||||||
|
func(*args, **kwargs) # cryptography
|
||||||
|
finally:
|
||||||
|
crypto.HAS_CRYPTODOME = has_cryptodome
|
||||||
|
crypto.HAS_CRYPTOGRAPHY = has_cryptography
|
||||||
return run_test
|
return run_test
|
||||||
|
|
||||||
|
|
||||||
|
@ -67,7 +95,11 @@ class Test_bitcoin(ElectrumTestCase):
|
||||||
|
|
||||||
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.
|
||||||
self.assertTrue(bool(crypto.AES))
|
self.assertTrue(bool(crypto.HAS_CRYPTODOME))
|
||||||
|
|
||||||
|
def test_cryptography_is_available(self):
|
||||||
|
# we want the unit testing framework to test with cryptography available.
|
||||||
|
self.assertTrue(bool(crypto.HAS_CRYPTOGRAPHY))
|
||||||
|
|
||||||
@needs_test_with_all_aes_implementations
|
@needs_test_with_all_aes_implementations
|
||||||
def test_crypto(self):
|
def test_crypto(self):
|
||||||
|
@ -223,6 +255,34 @@ class Test_bitcoin(ElectrumTestCase):
|
||||||
with self.assertRaises(InvalidPassword):
|
with self.assertRaises(InvalidPassword):
|
||||||
crypto.pw_decode(enc, wrong_password, version=version)
|
crypto.pw_decode(enc, wrong_password, version=version)
|
||||||
|
|
||||||
|
@needs_test_with_all_chacha20_implementations
|
||||||
|
def test_chacha20_poly1305_encrypt(self):
|
||||||
|
key = bytes.fromhex('37326d9d69a83b815ddfd947d21b0dd39111e5b6a5a44042c44d570ea03e3179')
|
||||||
|
nonce = bytes.fromhex('010203040506070809101112')
|
||||||
|
associated_data = bytes.fromhex('30c9572d4305d4f3ccb766b1db884da6f1e0086f55136a39740700c272095717')
|
||||||
|
data = bytes.fromhex('4a6cd75da76cedf0a8a47e3a5734a328')
|
||||||
|
self.assertEqual(bytes.fromhex('90fb51fcde1fbe4013500bd7a32280445d80ee21f0aa3acd30df72cf609de064'),
|
||||||
|
crypto.chacha20_poly1305_encrypt(key=key, nonce=nonce, associated_data=associated_data, data=data))
|
||||||
|
|
||||||
|
@needs_test_with_all_chacha20_implementations
|
||||||
|
def test_chacha20_poly1305_decrypt(self):
|
||||||
|
key = bytes.fromhex('37326d9d69a83b815ddfd947d21b0dd39111e5b6a5a44042c44d570ea03e3179')
|
||||||
|
nonce = bytes.fromhex('010203040506070809101112')
|
||||||
|
associated_data = bytes.fromhex('30c9572d4305d4f3ccb766b1db884da6f1e0086f55136a39740700c272095717')
|
||||||
|
data = bytes.fromhex('90fb51fcde1fbe4013500bd7a32280445d80ee21f0aa3acd30df72cf609de064')
|
||||||
|
self.assertEqual(bytes.fromhex('4a6cd75da76cedf0a8a47e3a5734a328'),
|
||||||
|
crypto.chacha20_poly1305_decrypt(key=key, nonce=nonce, associated_data=associated_data, data=data))
|
||||||
|
with self.assertRaises(ValueError):
|
||||||
|
crypto.chacha20_poly1305_decrypt(key=key, nonce=nonce, associated_data=b'', data=data)
|
||||||
|
|
||||||
|
@needs_test_with_all_chacha20_implementations
|
||||||
|
def test_chacha20_encrypt(self):
|
||||||
|
key = bytes.fromhex('37326d9d69a83b815ddfd947d21b0dd39111e5b6a5a44042c44d570ea03e3179')
|
||||||
|
nonce = bytes.fromhex('0102030405060708')
|
||||||
|
data = bytes.fromhex('38a0e0a7c865fe9ca31f0730cfcab610f18e6da88dc3790f1d243f711a257c78')
|
||||||
|
self.assertEqual(bytes.fromhex('f62fbd74d197323c7c3d5658476a884d38ee6f4b5500add1e8dc80dcd9c15dff'),
|
||||||
|
crypto.chacha20_encrypt(key=key, nonce=nonce, data=data))
|
||||||
|
|
||||||
def test_sha256d(self):
|
def test_sha256d(self):
|
||||||
self.assertEqual(b'\x95MZI\xfdp\xd9\xb8\xbc\xdb5\xd2R&x)\x95\x7f~\xf7\xfalt\xf8\x84\x19\xbd\xc5\xe8"\t\xf4',
|
self.assertEqual(b'\x95MZI\xfdp\xd9\xb8\xbc\xdb5\xd2R&x)\x95\x7f~\xf7\xfalt\xf8\x84\x19\xbd\xc5\xe8"\t\xf4',
|
||||||
sha256d(u"test"))
|
sha256d(u"test"))
|
||||||
|
|
|
@ -28,6 +28,7 @@ from electrum.logging import console_stderr_handler
|
||||||
from electrum.lnworker import PaymentInfo, RECEIVED, PR_UNPAID
|
from electrum.lnworker import PaymentInfo, RECEIVED, PR_UNPAID
|
||||||
|
|
||||||
from .test_lnchannel import create_test_channels
|
from .test_lnchannel import create_test_channels
|
||||||
|
from .test_bitcoin import needs_test_with_all_chacha20_implementations
|
||||||
from . import ElectrumTestCase
|
from . import ElectrumTestCase
|
||||||
|
|
||||||
def keypair():
|
def keypair():
|
||||||
|
@ -246,6 +247,7 @@ class TestPeer(ElectrumTestCase):
|
||||||
with self.assertRaises(concurrent.futures.CancelledError):
|
with self.assertRaises(concurrent.futures.CancelledError):
|
||||||
run(f())
|
run(f())
|
||||||
|
|
||||||
|
@needs_test_with_all_chacha20_implementations
|
||||||
def test_reestablish_with_old_state(self):
|
def test_reestablish_with_old_state(self):
|
||||||
alice_channel, bob_channel = create_test_channels()
|
alice_channel, bob_channel = create_test_channels()
|
||||||
alice_channel_0, bob_channel_0 = create_test_channels() # these are identical
|
alice_channel_0, bob_channel_0 = create_test_channels() # these are identical
|
||||||
|
@ -279,6 +281,7 @@ class TestPeer(ElectrumTestCase):
|
||||||
with self.assertRaises(concurrent.futures.CancelledError):
|
with self.assertRaises(concurrent.futures.CancelledError):
|
||||||
run(f())
|
run(f())
|
||||||
|
|
||||||
|
@needs_test_with_all_chacha20_implementations
|
||||||
def test_payment(self):
|
def test_payment(self):
|
||||||
alice_channel, bob_channel = create_test_channels()
|
alice_channel, bob_channel = create_test_channels()
|
||||||
p1, p2, w1, w2, _q1, _q2 = self.prepare_peers(alice_channel, bob_channel)
|
p1, p2, w1, w2, _q1, _q2 = self.prepare_peers(alice_channel, bob_channel)
|
||||||
|
@ -293,6 +296,7 @@ class TestPeer(ElectrumTestCase):
|
||||||
with self.assertRaises(concurrent.futures.CancelledError):
|
with self.assertRaises(concurrent.futures.CancelledError):
|
||||||
run(f())
|
run(f())
|
||||||
|
|
||||||
|
@needs_test_with_all_chacha20_implementations
|
||||||
def test_close(self):
|
def test_close(self):
|
||||||
alice_channel, bob_channel = create_test_channels()
|
alice_channel, bob_channel = create_test_channels()
|
||||||
p1, p2, w1, w2, _q1, _q2 = self.prepare_peers(alice_channel, bob_channel)
|
p1, p2, w1, w2, _q1, _q2 = self.prepare_peers(alice_channel, bob_channel)
|
||||||
|
|
|
@ -12,6 +12,8 @@ from electrum.constants import BitcoinTestnet
|
||||||
from electrum.simple_config import SimpleConfig
|
from electrum.simple_config import SimpleConfig
|
||||||
|
|
||||||
from . import TestCaseForTestnet
|
from . import TestCaseForTestnet
|
||||||
|
from .test_bitcoin import needs_test_with_all_chacha20_implementations
|
||||||
|
|
||||||
|
|
||||||
class Test_LNRouter(TestCaseForTestnet):
|
class Test_LNRouter(TestCaseForTestnet):
|
||||||
|
|
||||||
|
@ -108,6 +110,7 @@ class Test_LNRouter(TestCaseForTestnet):
|
||||||
self._loop_thread.join(timeout=1)
|
self._loop_thread.join(timeout=1)
|
||||||
cdb.sql_thread.join(timeout=1)
|
cdb.sql_thread.join(timeout=1)
|
||||||
|
|
||||||
|
@needs_test_with_all_chacha20_implementations
|
||||||
def test_new_onion_packet(self):
|
def test_new_onion_packet(self):
|
||||||
# test vector from bolt-04
|
# test vector from bolt-04
|
||||||
payment_path_pubkeys = [
|
payment_path_pubkeys = [
|
||||||
|
@ -140,6 +143,7 @@ class Test_LNRouter(TestCaseForTestnet):
|
||||||
self.assertEqual(bfh('0002eec7245d6b7d2ccb30380bfbe2a3648cd7a942653f5aa340edcea1f283686619e5f14350c2a76fc232b5e46d421e9615471ab9e0bc887beff8c95fdb878f7b3a71da571226458c510bbadd1276f045c21c520a07d35da256ef75b4367962437b0dd10f7d61ab590531cf08000178a333a347f8b4072e216400406bdf3bf038659793a86cae5f52d32f3438527b47a1cfc54285a8afec3a4c9f3323db0c946f5d4cb2ce721caad69320c3a469a202f3e468c67eaf7a7cda226d0fd32f7b48084dca885d15222e60826d5d971f64172d98e0760154400958f00e86697aa1aa9d41bee8119a1ec866abe044a9ad635778ba61fc0776dc832b39451bd5d35072d2269cf9b040d6ba38b54ec35f81d7fc67678c3be47274f3c4cc472aff005c3469eb3bc140769ed4c7f0218ff8c6c7dd7221d189c65b3b9aaa71a01484b122846c7c7b57e02e679ea8469b70e14fe4f70fee4d87b910cf144be6fe48eef24da475c0b0bcc6565ae82cd3f4e3b24c76eaa5616c6111343306ab35c1fe5ca4a77c0e314ed7dba39d6f1e0de791719c241a939cc493bea2bae1c1e932679ea94d29084278513c77b899cc98059d06a27d171b0dbdf6bee13ddc4fc17a0c4d2827d488436b57baa167544138ca2e64a11b43ac8a06cd0c2fba2d4d900ed2d9205305e2d7383cc98dacb078133de5f6fb6bed2ef26ba92cea28aafc3b9948dd9ae5559e8bd6920b8cea462aa445ca6a95e0e7ba52961b181c79e73bd581821df2b10173727a810c92b83b5ba4a0403eb710d2ca10689a35bec6c3a708e9e92f7d78ff3c5d9989574b00c6736f84c199256e76e19e78f0c98a9d580b4a658c84fc8f2096c2fbea8f5f8c59d0fdacb3be2802ef802abbecb3aba4acaac69a0e965abd8981e9896b1f6ef9d60f7a164b371af869fd0e48073742825e9434fc54da837e120266d53302954843538ea7c6c3dbfb4ff3b2fdbe244437f2a153ccf7bdb4c92aa08102d4f3cff2ae5ef86fab4653595e6a5837fa2f3e29f27a9cde5966843fb847a4a61f1e76c281fe8bb2b0a181d096100db5a1a5ce7a910238251a43ca556712eaadea167fb4d7d75825e440f3ecd782036d7574df8bceacb397abefc5f5254d2722215c53ff54af8299aaaad642c6d72a14d27882d9bbd539e1cc7a527526ba89b8c037ad09120e98ab042d3e8652b31ae0e478516bfaf88efca9f3676ffe99d2819dcaeb7610a626695f53117665d267d3f7abebd6bbd6733f645c72c389f03855bdf1e4b8075b516569b118233a0f0971d24b83113c0b096f5216a207ca99a7cddc81c130923fe3d91e7508c9ac5f2e914ff5dccab9e558566fa14efb34ac98d878580814b94b73acbfde9072f30b881f7f0fff42d4045d1ace6322d86a97d164aa84d93a60498065cc7c20e636f5862dc81531a88c60305a2e59a985be327a6902e4bed986dbf4a0b50c217af0ea7fdf9ab37f9ea1a1aaa72f54cf40154ea9b269f1a7c09f9f43245109431a175d50e2db0132337baa0ef97eed0fcf20489da36b79a1172faccc2f7ded7c60e00694282d93359c4682135642bc81f433574aa8ef0c97b4ade7ca372c5ffc23c7eddd839bab4e0f14d6df15c9dbeab176bec8b5701cf054eb3072f6dadc98f88819042bf10c407516ee58bce33fbe3b3d86a54255e577db4598e30a135361528c101683a5fcde7e8ba53f3456254be8f45fe3a56120ae96ea3773631fcb3873aa3abd91bcff00bd38bd43697a2e789e00da6077482e7b1b1a677b5afae4c54e6cbdf7377b694eb7d7a5b913476a5be923322d3de06060fd5e819635232a2cf4f0731da13b8546d1d6d4f8d75b9fce6c2341a71b0ea6f780df54bfdb0dd5cd9855179f602f917265f21f9190c70217774a6fbaaa7d63ad64199f4664813b955cff954949076dcf'),
|
self.assertEqual(bfh('0002eec7245d6b7d2ccb30380bfbe2a3648cd7a942653f5aa340edcea1f283686619e5f14350c2a76fc232b5e46d421e9615471ab9e0bc887beff8c95fdb878f7b3a71da571226458c510bbadd1276f045c21c520a07d35da256ef75b4367962437b0dd10f7d61ab590531cf08000178a333a347f8b4072e216400406bdf3bf038659793a86cae5f52d32f3438527b47a1cfc54285a8afec3a4c9f3323db0c946f5d4cb2ce721caad69320c3a469a202f3e468c67eaf7a7cda226d0fd32f7b48084dca885d15222e60826d5d971f64172d98e0760154400958f00e86697aa1aa9d41bee8119a1ec866abe044a9ad635778ba61fc0776dc832b39451bd5d35072d2269cf9b040d6ba38b54ec35f81d7fc67678c3be47274f3c4cc472aff005c3469eb3bc140769ed4c7f0218ff8c6c7dd7221d189c65b3b9aaa71a01484b122846c7c7b57e02e679ea8469b70e14fe4f70fee4d87b910cf144be6fe48eef24da475c0b0bcc6565ae82cd3f4e3b24c76eaa5616c6111343306ab35c1fe5ca4a77c0e314ed7dba39d6f1e0de791719c241a939cc493bea2bae1c1e932679ea94d29084278513c77b899cc98059d06a27d171b0dbdf6bee13ddc4fc17a0c4d2827d488436b57baa167544138ca2e64a11b43ac8a06cd0c2fba2d4d900ed2d9205305e2d7383cc98dacb078133de5f6fb6bed2ef26ba92cea28aafc3b9948dd9ae5559e8bd6920b8cea462aa445ca6a95e0e7ba52961b181c79e73bd581821df2b10173727a810c92b83b5ba4a0403eb710d2ca10689a35bec6c3a708e9e92f7d78ff3c5d9989574b00c6736f84c199256e76e19e78f0c98a9d580b4a658c84fc8f2096c2fbea8f5f8c59d0fdacb3be2802ef802abbecb3aba4acaac69a0e965abd8981e9896b1f6ef9d60f7a164b371af869fd0e48073742825e9434fc54da837e120266d53302954843538ea7c6c3dbfb4ff3b2fdbe244437f2a153ccf7bdb4c92aa08102d4f3cff2ae5ef86fab4653595e6a5837fa2f3e29f27a9cde5966843fb847a4a61f1e76c281fe8bb2b0a181d096100db5a1a5ce7a910238251a43ca556712eaadea167fb4d7d75825e440f3ecd782036d7574df8bceacb397abefc5f5254d2722215c53ff54af8299aaaad642c6d72a14d27882d9bbd539e1cc7a527526ba89b8c037ad09120e98ab042d3e8652b31ae0e478516bfaf88efca9f3676ffe99d2819dcaeb7610a626695f53117665d267d3f7abebd6bbd6733f645c72c389f03855bdf1e4b8075b516569b118233a0f0971d24b83113c0b096f5216a207ca99a7cddc81c130923fe3d91e7508c9ac5f2e914ff5dccab9e558566fa14efb34ac98d878580814b94b73acbfde9072f30b881f7f0fff42d4045d1ace6322d86a97d164aa84d93a60498065cc7c20e636f5862dc81531a88c60305a2e59a985be327a6902e4bed986dbf4a0b50c217af0ea7fdf9ab37f9ea1a1aaa72f54cf40154ea9b269f1a7c09f9f43245109431a175d50e2db0132337baa0ef97eed0fcf20489da36b79a1172faccc2f7ded7c60e00694282d93359c4682135642bc81f433574aa8ef0c97b4ade7ca372c5ffc23c7eddd839bab4e0f14d6df15c9dbeab176bec8b5701cf054eb3072f6dadc98f88819042bf10c407516ee58bce33fbe3b3d86a54255e577db4598e30a135361528c101683a5fcde7e8ba53f3456254be8f45fe3a56120ae96ea3773631fcb3873aa3abd91bcff00bd38bd43697a2e789e00da6077482e7b1b1a677b5afae4c54e6cbdf7377b694eb7d7a5b913476a5be923322d3de06060fd5e819635232a2cf4f0731da13b8546d1d6d4f8d75b9fce6c2341a71b0ea6f780df54bfdb0dd5cd9855179f602f917265f21f9190c70217774a6fbaaa7d63ad64199f4664813b955cff954949076dcf'),
|
||||||
packet.to_bytes())
|
packet.to_bytes())
|
||||||
|
|
||||||
|
@needs_test_with_all_chacha20_implementations
|
||||||
def test_process_onion_packet(self):
|
def test_process_onion_packet(self):
|
||||||
# this test is not from bolt-04, but is based on the one there;
|
# this test is not from bolt-04, but is based on the one there;
|
||||||
# except here we have the privkeys for these pubkeys
|
# except here we have the privkeys for these pubkeys
|
||||||
|
@ -184,6 +188,7 @@ class Test_LNRouter(TestCaseForTestnet):
|
||||||
self.assertEqual(hops_data[i].per_hop.to_bytes(), processed_packet.hop_data.per_hop.to_bytes())
|
self.assertEqual(hops_data[i].per_hop.to_bytes(), processed_packet.hop_data.per_hop.to_bytes())
|
||||||
packet = processed_packet.next_packet
|
packet = processed_packet.next_packet
|
||||||
|
|
||||||
|
@needs_test_with_all_chacha20_implementations
|
||||||
def test_decode_onion_error(self):
|
def test_decode_onion_error(self):
|
||||||
# test vector from bolt-04
|
# test vector from bolt-04
|
||||||
payment_path_pubkeys = [
|
payment_path_pubkeys = [
|
||||||
|
|
|
@ -5,10 +5,12 @@ from electrum.lnutil import LNPeerAddr
|
||||||
from electrum.lntransport import LNResponderTransport, LNTransport
|
from electrum.lntransport import LNResponderTransport, LNTransport
|
||||||
|
|
||||||
from . import ElectrumTestCase
|
from . import ElectrumTestCase
|
||||||
|
from .test_bitcoin import needs_test_with_all_chacha20_implementations
|
||||||
|
|
||||||
|
|
||||||
class TestLNTransport(ElectrumTestCase):
|
class TestLNTransport(ElectrumTestCase):
|
||||||
|
|
||||||
|
@needs_test_with_all_chacha20_implementations
|
||||||
def test_responder(self):
|
def test_responder(self):
|
||||||
# local static
|
# local static
|
||||||
ls_priv=bytes.fromhex('2121212121212121212121212121212121212121212121212121212121212121')
|
ls_priv=bytes.fromhex('2121212121212121212121212121212121212121212121212121212121212121')
|
||||||
|
@ -37,6 +39,7 @@ class TestLNTransport(ElectrumTestCase):
|
||||||
transport = LNResponderTransport(ls_priv, Reader(), Writer())
|
transport = LNResponderTransport(ls_priv, Reader(), Writer())
|
||||||
asyncio.get_event_loop().run_until_complete(transport.handshake(epriv=e_priv))
|
asyncio.get_event_loop().run_until_complete(transport.handshake(epriv=e_priv))
|
||||||
|
|
||||||
|
@needs_test_with_all_chacha20_implementations
|
||||||
def test_loop(self):
|
def test_loop(self):
|
||||||
loop = asyncio.get_event_loop()
|
loop = asyncio.get_event_loop()
|
||||||
responder_shaked = asyncio.Event()
|
responder_shaked = asyncio.Event()
|
||||||
|
|
7
setup.py
7
setup.py
|
@ -53,8 +53,13 @@ if platform.system() in ['Linux', 'FreeBSD', 'DragonFly']:
|
||||||
extras_require = {
|
extras_require = {
|
||||||
'hardware': requirements_hw,
|
'hardware': requirements_hw,
|
||||||
'gui': ['pyqt5'],
|
'gui': ['pyqt5'],
|
||||||
|
'crypto': ['pycryptodomex>=3.7'],
|
||||||
|
'tests': ['pycryptodomex>=3.7', 'cryptography>=2.1'],
|
||||||
}
|
}
|
||||||
extras_require['full'] = [pkg for sublist in list(extras_require.values()) for pkg in sublist]
|
# 'full' extra that tries to grab everything an enduser would need (except for libsecp256k1...)
|
||||||
|
extras_require['full'] = [pkg for sublist in ['hardware', 'gui', 'crypto'] for pkg in sublist]
|
||||||
|
# legacy. keep 'fast' extra working
|
||||||
|
extras_require['fast'] = extras_require['crypto']
|
||||||
|
|
||||||
|
|
||||||
setup(
|
setup(
|
||||||
|
|
2
tox.ini
2
tox.ini
|
@ -9,4 +9,4 @@ commands=
|
||||||
coverage run --source=electrum '--omit=electrum/gui/*,electrum/plugins/*,electrum/scripts/*,electrum/tests/*' -m py.test -v
|
coverage run --source=electrum '--omit=electrum/gui/*,electrum/plugins/*,electrum/scripts/*,electrum/tests/*' -m py.test -v
|
||||||
coverage report
|
coverage report
|
||||||
extras=
|
extras=
|
||||||
fast
|
tests
|
||||||
|
|
Loading…
Add table
Reference in a new issue