From 504d092258bdf677b966f64f9d8658f0bf251752 Mon Sep 17 00:00:00 2001 From: Mehdi Samsami Date: Sun, 11 Jun 2023 04:41:46 +0330 Subject: [PATCH 01/21] add validator for eth addresses --- validators/__init__.py | 2 ++ validators/eth_address.py | 55 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 57 insertions(+) create mode 100644 validators/eth_address.py diff --git a/validators/__init__.py b/validators/__init__.py index c78c27ab..7ba5477d 100644 --- a/validators/__init__.py +++ b/validators/__init__.py @@ -13,6 +13,7 @@ from .card import amex, card_number, diners, discover, jcb, mastercard, unionpay, visa from .domain import domain from .email import email +from .eth_address import eth_address from .hashes import md5, sha1, sha224, sha256, sha512 from .hostname import hostname from .iban import iban @@ -30,6 +31,7 @@ "amex", "between", "btc_address", + "eth_address", "card_number", "diners", "discover", diff --git a/validators/eth_address.py b/validators/eth_address.py new file mode 100644 index 00000000..3c8b9e2a --- /dev/null +++ b/validators/eth_address.py @@ -0,0 +1,55 @@ +"""ETH Address.""" +# -*- coding: utf-8 -*- + +# standard +import re + +from sha3 import keccak_256 + +# local +from .utils import validator + + +def _validate_eth_checksum_address(addr: str): + """Validate ETH type checksum address.""" + addr = addr.replace("0x", "") + addr_hash = keccak_256(addr.lower().encode("ascii")).hexdigest() + + for i in range(0, 40): + if ((int(addr_hash[i], 16) > 7 and addr[i].upper() != addr[i]) or + (int(addr_hash[i], 16) <= 7 and addr[i].lower() != addr[i])): + return False + return True + + +@validator +def eth_address(value: str, /): + """Return whether or not given value is a valid ethereum address. + + Full validation is implemented for ERC20 addresses. + + Examples: + >>> eth_address('0x9cc14ba4f9f68ca159ea4ebf2c292a808aaeb598') + # Output: True + >>> eth_address('0x8Ba1f109551bD432803012645Ac136ddd64DBa72') + # Output: ValidationFailure(func=eth_address, args=...) + + Args: + value: + Ethereum address string to validate. + + Returns: + (Literal[True]): + If `value` is a valid ethereum address. + (ValidationFailure): + If `value` is an invalid ethereum address. + + """ + if not value: + return False + + return ( + re.compile(r"^0x[0-9a-f]{40}$").match(value) or + re.compile(r"^0x[0-9A-F]{40}$").match(value) or + _validate_eth_checksum_address(value) + ) From cef562cafb076ef5c9c1f6cc1b1a85a520498e5c Mon Sep 17 00:00:00 2001 From: Mehdi Samsami Date: Sun, 11 Jun 2023 04:42:26 +0330 Subject: [PATCH 02/21] add test for eth address validator --- tests/test_eth_address.py | 47 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 47 insertions(+) create mode 100644 tests/test_eth_address.py diff --git a/tests/test_eth_address.py b/tests/test_eth_address.py new file mode 100644 index 00000000..984858de --- /dev/null +++ b/tests/test_eth_address.py @@ -0,0 +1,47 @@ +"""Test ETH address.""" +# -*- coding: utf-8 -*- + +# external +import pytest + +# local +from validators import eth_address, ValidationFailure + + +@pytest.mark.parametrize( + "value", + [ + "0x8ba1f109551bd432803012645ac136ddd64dba72", + "0x9cc14ba4f9f68ca159ea4ebf2c292a808aaeb598", + "0x5AEDA56215b167893e80B4fE645BA6d5Bab767DE", + "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2", + "742d35Cc6634C0532925a3b844Bc454e4438f44e", + "0x742d35Cc6634C0532925a3b844Bc454e4438f44e", + "0x1f9840a85d5aF5bf1D1762F925BDADdC4201F984", + "0x1234567890123456789012345678901234567890", + "0x57Ab1ec28D129707052df4dF418D58a2D46d5f51", + ], +) +def test_returns_true_on_valid_eth_address(value: str): + """Test returns true on valid eth address.""" + assert eth_address(value) + + +@pytest.mark.parametrize( + "value", + [ + "0x742d35Cc6634C0532925a3b844Bc454e4438f44g", + "0x742d35Cc6634C0532925a3b844Bc454e4438f44", + "0xAbcdefg1234567890Abcdefg1234567890Abcdefg", + "0x7c8EE9977c6f96b6b9774b3e8e4Cc9B93B12b2c72" + "0x80fBD7F8B3f81D0e1d6EACAb69AF104A6508AFB1", + "0x7c8EE9977c6f96b6b9774b3e8e4Cc9B93B12b2c7g", + "0x8Ba1f109551bD432803012645Ac136ddd64DBa72", + "0x7c8EE9977c6f96b6b9774b3e8e4Cc9B93B12b2c", + "0x7Fb21a171205f3B8d8E4d88A2d2f8A56E45DdB5c" + "validators.eth", + ], +) +def test_returns_failed_validation_on_invalid_eth_address(value: str): + """Test returns failed validation on invalid eth address.""" + assert isinstance(eth_address(value), ValidationFailure) From 498166ccc90c1febd2c4d602c23534361f60723d Mon Sep 17 00:00:00 2001 From: Mehdi Samsami Date: Sun, 11 Jun 2023 04:59:59 +0330 Subject: [PATCH 03/21] add pysha3 dependency --- poetry.lock | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/poetry.lock b/poetry.lock index 7f859f4c..929d4922 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1087,6 +1087,37 @@ nodeenv = ">=1.6.0" all = ["twine (>=3.4.1)"] dev = ["twine (>=3.4.1)"] +[[package]] +name = "pysha3" +version = "1.0.2" +description = "SHA-3 (Keccak) for Python 2.7 - 3.5" +category = "dev" +optional = false +python-versions = "*" +files = [ + {file = "pysha3-1.0.2-cp27-cp27m-manylinux1_i686.whl", hash = "sha256:6e6a84efb7856f5d760ee55cd2b446972cb7b835676065f6c4f694913ea8f8d9"}, + {file = "pysha3-1.0.2-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:f9046d59b3e72aa84f6dae83a040bd1184ebd7fef4e822d38186a8158c89e3cf"}, + {file = "pysha3-1.0.2-cp27-cp27m-win32.whl", hash = "sha256:9fdd28884c5d0b4edfed269b12badfa07f1c89dbc5c9c66dd279833894a9896b"}, + {file = "pysha3-1.0.2-cp27-cp27m-win_amd64.whl", hash = "sha256:41be70b06c8775a9e4d4eeb52f2f6a3f356f17539a54eac61f43a29e42fd453d"}, + {file = "pysha3-1.0.2-cp27-cp27mu-manylinux1_i686.whl", hash = "sha256:68c3a60a39f9179b263d29e221c1bd6e01353178b14323c39cc70593c30f21c5"}, + {file = "pysha3-1.0.2-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:59111c08b8f34495575d12e5f2ce3bafb98bea470bc81e70c8b6df99aef0dd2f"}, + {file = "pysha3-1.0.2-cp33-cp33m-win32.whl", hash = "sha256:571a246308a7b63f15f5aa9651f99cf30f2a6acba18eddf28f1510935968b603"}, + {file = "pysha3-1.0.2-cp33-cp33m-win_amd64.whl", hash = "sha256:93abd775dac570cb9951c4e423bcb2bc6303a9d1dc0dc2b7afa2dd401d195b24"}, + {file = "pysha3-1.0.2-cp34-cp34m-manylinux1_i686.whl", hash = "sha256:11a2ba7a2e1d9669d0052fc8fb30f5661caed5512586ecbeeaf6bf9478ab5c48"}, + {file = "pysha3-1.0.2-cp34-cp34m-manylinux1_x86_64.whl", hash = "sha256:5ec8da7c5c70a53b5fa99094af3ba8d343955b212bc346a0d25f6ff75853999f"}, + {file = "pysha3-1.0.2-cp34-cp34m-win32.whl", hash = "sha256:9c778fa8b161dc9348dc5cc361e94d54aa5ff18413788f4641f6600d4893a608"}, + {file = "pysha3-1.0.2-cp34-cp34m-win_amd64.whl", hash = "sha256:fd7e66999060d079e9c0e8893e78d8017dad4f59721f6fe0be6307cd32127a07"}, + {file = "pysha3-1.0.2-cp35-cp35m-manylinux1_i686.whl", hash = "sha256:827b308dc025efe9b6b7bae36c2e09ed0118a81f792d888548188e97b9bf9a3d"}, + {file = "pysha3-1.0.2-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:4416f16b0f1605c25f627966f76873e432971824778b369bd9ce1bb63d6566d9"}, + {file = "pysha3-1.0.2-cp35-cp35m-win32.whl", hash = "sha256:c93a2676e6588abcfaecb73eb14485c81c63b94fca2000a811a7b4fb5937b8e8"}, + {file = "pysha3-1.0.2-cp35-cp35m-win_amd64.whl", hash = "sha256:684cb01d87ed6ff466c135f1c83e7e4042d0fc668fa20619f581e6add1d38d77"}, + {file = "pysha3-1.0.2-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:386998ee83e313b6911327174e088021f9f2061cbfa1651b97629b761e9ef5c4"}, + {file = "pysha3-1.0.2-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:c7c2adcc43836223680ebdf91f1d3373543dc32747c182c8ca2e02d1b69ce030"}, + {file = "pysha3-1.0.2-cp36-cp36m-win32.whl", hash = "sha256:cd5c961b603bd2e6c2b5ef9976f3238a561c58569945d4165efb9b9383b050ef"}, + {file = "pysha3-1.0.2-cp36-cp36m-win_amd64.whl", hash = "sha256:0060a66be16665d90c432f55a0ba1f6480590cfb7d2ad389e688a399183474f0"}, + {file = "pysha3-1.0.2.tar.gz", hash = "sha256:fe988e73f2ce6d947220624f04d467faf05f1bbdbc64b0a201296bb3af92739e"}, +] + [[package]] name = "pytest" version = "7.3.0" From 02267c32fc2a1d9acefcdb130858f2cfb2019bd4 Mon Sep 17 00:00:00 2001 From: Mehdi Samsami Date: Mon, 12 Jun 2023 13:42:07 +0330 Subject: [PATCH 04/21] move eth and btc validators to a new submodule --- validators/__init__.py | 4 ++-- validators/{ => crypto_addresses}/btc_address.py | 0 validators/{ => crypto_addresses}/eth_address.py | 0 3 files changed, 2 insertions(+), 2 deletions(-) rename validators/{ => crypto_addresses}/btc_address.py (100%) rename validators/{ => crypto_addresses}/eth_address.py (100%) diff --git a/validators/__init__.py b/validators/__init__.py index 7ba5477d..2dfd7063 100644 --- a/validators/__init__.py +++ b/validators/__init__.py @@ -9,11 +9,11 @@ # local from .between import between -from .btc_address import btc_address +from crypto_addresses.btc_address import btc_address from .card import amex, card_number, diners, discover, jcb, mastercard, unionpay, visa from .domain import domain from .email import email -from .eth_address import eth_address +from crypto_addresses.eth_address import eth_address from .hashes import md5, sha1, sha224, sha256, sha512 from .hostname import hostname from .iban import iban diff --git a/validators/btc_address.py b/validators/crypto_addresses/btc_address.py similarity index 100% rename from validators/btc_address.py rename to validators/crypto_addresses/btc_address.py diff --git a/validators/eth_address.py b/validators/crypto_addresses/eth_address.py similarity index 100% rename from validators/eth_address.py rename to validators/crypto_addresses/eth_address.py From 8a66692a64cc52c2b5026d159d8bae00e1507f9e Mon Sep 17 00:00:00 2001 From: Mehdi Samsami Date: Mon, 12 Jun 2023 13:42:28 +0330 Subject: [PATCH 05/21] move eth and btc validators' tests to a new submodule --- tests/{ => crypto_addresses}/test_btc_address.py | 0 tests/{ => crypto_addresses}/test_eth_address.py | 0 2 files changed, 0 insertions(+), 0 deletions(-) rename tests/{ => crypto_addresses}/test_btc_address.py (100%) rename tests/{ => crypto_addresses}/test_eth_address.py (100%) diff --git a/tests/test_btc_address.py b/tests/crypto_addresses/test_btc_address.py similarity index 100% rename from tests/test_btc_address.py rename to tests/crypto_addresses/test_btc_address.py diff --git a/tests/test_eth_address.py b/tests/crypto_addresses/test_eth_address.py similarity index 100% rename from tests/test_eth_address.py rename to tests/crypto_addresses/test_eth_address.py From 875dcd351d05ef68c116f935d2eb00509209d1a9 Mon Sep 17 00:00:00 2001 From: Mehdi Samsami Date: Mon, 12 Jun 2023 13:48:22 +0330 Subject: [PATCH 06/21] add init files for new submodules --- tests/crypto_addresses/__init__.py | 4 ++++ validators/crypto_addresses/__init__.py | 10 ++++++++++ 2 files changed, 14 insertions(+) create mode 100644 tests/crypto_addresses/__init__.py create mode 100644 validators/crypto_addresses/__init__.py diff --git a/tests/crypto_addresses/__init__.py b/tests/crypto_addresses/__init__.py new file mode 100644 index 00000000..956d8177 --- /dev/null +++ b/tests/crypto_addresses/__init__.py @@ -0,0 +1,4 @@ +"""Test crypto addresses.""" +# -*- coding: utf-8 -*- + +# isort: skip_file diff --git a/validators/crypto_addresses/__init__.py b/validators/crypto_addresses/__init__.py new file mode 100644 index 00000000..b6b90b36 --- /dev/null +++ b/validators/crypto_addresses/__init__.py @@ -0,0 +1,10 @@ +"""Crypto addresses.""" +# -*- coding: utf-8 -*- + +# isort: skip_file + +# local +from .btc_address import btc_address +from .eth_address import eth_address + +__all__ = ("btc_address", "eth_address") From ec1071f90f0462dd596bda7ffa85d999397e5d05 Mon Sep 17 00:00:00 2001 From: Mehdi Samsami Date: Mon, 12 Jun 2023 13:54:22 +0330 Subject: [PATCH 07/21] add trx validator to init --- validators/crypto_addresses/__init__.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/validators/crypto_addresses/__init__.py b/validators/crypto_addresses/__init__.py index b6b90b36..25f1183d 100644 --- a/validators/crypto_addresses/__init__.py +++ b/validators/crypto_addresses/__init__.py @@ -6,5 +6,6 @@ # local from .btc_address import btc_address from .eth_address import eth_address +from .trx_address import trx_address -__all__ = ("btc_address", "eth_address") +__all__ = ("btc_address", "eth_address", "trx_address") From 11ee0e1895f2220dadffb8e106eda3a0c1c2128a Mon Sep 17 00:00:00 2001 From: Mehdi Samsami Date: Mon, 12 Jun 2023 15:15:04 +0330 Subject: [PATCH 08/21] fix bug in importing validator --- validators/crypto_addresses/eth_address.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/validators/crypto_addresses/eth_address.py b/validators/crypto_addresses/eth_address.py index 3c8b9e2a..7e39a49f 100644 --- a/validators/crypto_addresses/eth_address.py +++ b/validators/crypto_addresses/eth_address.py @@ -7,7 +7,7 @@ from sha3 import keccak_256 # local -from .utils import validator +from validators.utils import validator def _validate_eth_checksum_address(addr: str): From a3b73671417cae497ed3e311c93a86c132639d8e Mon Sep 17 00:00:00 2001 From: Mehdi Samsami Date: Mon, 12 Jun 2023 15:16:09 +0330 Subject: [PATCH 09/21] revert moving btc validator and its tests to new submodules --- tests/{crypto_addresses => }/test_btc_address.py | 0 validators/{crypto_addresses => }/btc_address.py | 0 validators/crypto_addresses/__init__.py | 3 +-- 3 files changed, 1 insertion(+), 2 deletions(-) rename tests/{crypto_addresses => }/test_btc_address.py (100%) rename validators/{crypto_addresses => }/btc_address.py (100%) diff --git a/tests/crypto_addresses/test_btc_address.py b/tests/test_btc_address.py similarity index 100% rename from tests/crypto_addresses/test_btc_address.py rename to tests/test_btc_address.py diff --git a/validators/crypto_addresses/btc_address.py b/validators/btc_address.py similarity index 100% rename from validators/crypto_addresses/btc_address.py rename to validators/btc_address.py diff --git a/validators/crypto_addresses/__init__.py b/validators/crypto_addresses/__init__.py index 25f1183d..7acf0da7 100644 --- a/validators/crypto_addresses/__init__.py +++ b/validators/crypto_addresses/__init__.py @@ -4,8 +4,7 @@ # isort: skip_file # local -from .btc_address import btc_address from .eth_address import eth_address from .trx_address import trx_address -__all__ = ("btc_address", "eth_address", "trx_address") +__all__ = ("eth_address", "trx_address") From a97c5d186cb40db467b6311388735d4e1b13bc8e Mon Sep 17 00:00:00 2001 From: Mehdi Samsami Date: Mon, 12 Jun 2023 15:27:39 +0330 Subject: [PATCH 10/21] fix import --- validators/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/validators/__init__.py b/validators/__init__.py index 2dfd7063..20197e93 100644 --- a/validators/__init__.py +++ b/validators/__init__.py @@ -9,7 +9,7 @@ # local from .between import between -from crypto_addresses.btc_address import btc_address +from .btc_address import btc_address from .card import amex, card_number, diners, discover, jcb, mastercard, unionpay, visa from .domain import domain from .email import email From d0a1eac8721dc36d89b4526835be7efb3afbd8ed Mon Sep 17 00:00:00 2001 From: Mehdi Samsami Date: Sat, 17 Jun 2023 12:23:03 +0330 Subject: [PATCH 11/21] remove faulty test value --- tests/crypto_addresses/test_eth_address.py | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/crypto_addresses/test_eth_address.py b/tests/crypto_addresses/test_eth_address.py index 984858de..40b4d25f 100644 --- a/tests/crypto_addresses/test_eth_address.py +++ b/tests/crypto_addresses/test_eth_address.py @@ -15,7 +15,6 @@ "0x9cc14ba4f9f68ca159ea4ebf2c292a808aaeb598", "0x5AEDA56215b167893e80B4fE645BA6d5Bab767DE", "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2", - "742d35Cc6634C0532925a3b844Bc454e4438f44e", "0x742d35Cc6634C0532925a3b844Bc454e4438f44e", "0x1f9840a85d5aF5bf1D1762F925BDADdC4201F984", "0x1234567890123456789012345678901234567890", From e4128c9943788e7a338ca72bb9552f1a129637ee Mon Sep 17 00:00:00 2001 From: Mehdi Samsami Date: Sat, 17 Jun 2023 12:24:03 +0330 Subject: [PATCH 12/21] use relative import --- validators/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/validators/__init__.py b/validators/__init__.py index 20197e93..2df05054 100644 --- a/validators/__init__.py +++ b/validators/__init__.py @@ -13,7 +13,6 @@ from .card import amex, card_number, diners, discover, jcb, mastercard, unionpay, visa from .domain import domain from .email import email -from crypto_addresses.eth_address import eth_address from .hashes import md5, sha1, sha224, sha256, sha512 from .hostname import hostname from .iban import iban @@ -25,6 +24,7 @@ from .utils import validator, ValidationFailure from .uuid import uuid +from .crypto_addresses import eth_address from .i18n import es_cif, es_doi, es_nie, es_nif, fi_business_id, fi_ssn __all__ = ( From 1715ea38098e3650c322aa73851d08a5044344b0 Mon Sep 17 00:00:00 2001 From: Mehdi Samsami Date: Sat, 17 Jun 2023 12:24:49 +0330 Subject: [PATCH 13/21] remove trx_validator --- validators/crypto_addresses/__init__.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/validators/crypto_addresses/__init__.py b/validators/crypto_addresses/__init__.py index 7acf0da7..2b62a3bf 100644 --- a/validators/crypto_addresses/__init__.py +++ b/validators/crypto_addresses/__init__.py @@ -5,6 +5,5 @@ # local from .eth_address import eth_address -from .trx_address import trx_address -__all__ = ("eth_address", "trx_address") +__all__ = ("eth_address", ) From 8be96ea764cbd80775a5f0b39e1f47617a88cbc2 Mon Sep 17 00:00:00 2001 From: Mehdi Samsami Date: Sat, 17 Jun 2023 12:50:37 +0330 Subject: [PATCH 14/21] fix bugs in test values --- tests/crypto_addresses/test_eth_address.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/tests/crypto_addresses/test_eth_address.py b/tests/crypto_addresses/test_eth_address.py index 40b4d25f..4c0c8814 100644 --- a/tests/crypto_addresses/test_eth_address.py +++ b/tests/crypto_addresses/test_eth_address.py @@ -32,12 +32,11 @@ def test_returns_true_on_valid_eth_address(value: str): "0x742d35Cc6634C0532925a3b844Bc454e4438f44g", "0x742d35Cc6634C0532925a3b844Bc454e4438f44", "0xAbcdefg1234567890Abcdefg1234567890Abcdefg", - "0x7c8EE9977c6f96b6b9774b3e8e4Cc9B93B12b2c72" + "0x7c8EE9977c6f96b6b9774b3e8e4Cc9B93B12b2c72", "0x80fBD7F8B3f81D0e1d6EACAb69AF104A6508AFB1", "0x7c8EE9977c6f96b6b9774b3e8e4Cc9B93B12b2c7g", - "0x8Ba1f109551bD432803012645Ac136ddd64DBa72", "0x7c8EE9977c6f96b6b9774b3e8e4Cc9B93B12b2c", - "0x7Fb21a171205f3B8d8E4d88A2d2f8A56E45DdB5c" + "0x7Fb21a171205f3B8d8E4d88A2d2f8A56E45DdB5c", "validators.eth", ], ) From 8f2e25345ca05b6d812af4e021389193f5374d56 Mon Sep 17 00:00:00 2001 From: Mehdi Samsami Date: Sat, 17 Jun 2023 12:59:12 +0330 Subject: [PATCH 15/21] combine eth regex checks into one check --- validators/crypto_addresses/eth_address.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/validators/crypto_addresses/eth_address.py b/validators/crypto_addresses/eth_address.py index 7e39a49f..67686ab0 100644 --- a/validators/crypto_addresses/eth_address.py +++ b/validators/crypto_addresses/eth_address.py @@ -49,7 +49,6 @@ def eth_address(value: str, /): return False return ( - re.compile(r"^0x[0-9a-f]{40}$").match(value) or - re.compile(r"^0x[0-9A-F]{40}$").match(value) or + re.compile(r"^0x[0-9a-f]{40}$|^0x[0-9A-F]{40}$").match(value) or _validate_eth_checksum_address(value) ) From 04d9b8b87540a2f740652d5d5c2839b3121c18bb Mon Sep 17 00:00:00 2001 From: Mehdi Samsami Date: Sat, 17 Jun 2023 13:12:15 +0330 Subject: [PATCH 16/21] check length in checksum validation --- validators/crypto_addresses/eth_address.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/validators/crypto_addresses/eth_address.py b/validators/crypto_addresses/eth_address.py index 67686ab0..e181b0b7 100644 --- a/validators/crypto_addresses/eth_address.py +++ b/validators/crypto_addresses/eth_address.py @@ -15,6 +15,9 @@ def _validate_eth_checksum_address(addr: str): addr = addr.replace("0x", "") addr_hash = keccak_256(addr.lower().encode("ascii")).hexdigest() + if len(addr) != 40: + return False + for i in range(0, 40): if ((int(addr_hash[i], 16) > 7 and addr[i].upper() != addr[i]) or (int(addr_hash[i], 16) <= 7 and addr[i].lower() != addr[i])): From 3fffb0d57f4d6381917d7c257e0e6673445d61b4 Mon Sep 17 00:00:00 2001 From: Mehdi Samsami Date: Mon, 26 Jun 2023 12:07:26 +0330 Subject: [PATCH 17/21] use eth-hash instead of pysha3 --- poetry.lock | 42 ++++++---------------- pyproject.toml | 1 + validators/crypto_addresses/eth_address.py | 4 +-- 3 files changed, 14 insertions(+), 33 deletions(-) diff --git a/poetry.lock b/poetry.lock index 929d4922..0d537cdb 100644 --- a/poetry.lock +++ b/poetry.lock @@ -285,6 +285,17 @@ files = [ {file = "docutils-0.19.tar.gz", hash = "sha256:33995a6753c30b7f577febfc2c50411fec6aac7f7ffeb7c4cfe5991072dcf9e6"}, ] +[[package]] +name = "eth-hash" +version = "0.5.2" +description = "eth-hash: The Ethereum hashing function, keccak256, sometimes (erroneously) called sha3" +optional = false +python-versions = ">=3.7, <4" +files = [ + {file = "eth-hash-0.5.2.tar.gz", hash = "sha256:1b5f10eca7765cc385e1430eefc5ced6e2e463bb18d1365510e2e539c1a6fe4e"}, + {file = "eth_hash-0.5.2-py3-none-any.whl", hash = "sha256:251f62f6579a1e247561679d78df37548bd5f59908da0b159982bf8293ad32f0"}, +] + [[package]] name = "exceptiongroup" version = "1.1.1" @@ -1087,37 +1098,6 @@ nodeenv = ">=1.6.0" all = ["twine (>=3.4.1)"] dev = ["twine (>=3.4.1)"] -[[package]] -name = "pysha3" -version = "1.0.2" -description = "SHA-3 (Keccak) for Python 2.7 - 3.5" -category = "dev" -optional = false -python-versions = "*" -files = [ - {file = "pysha3-1.0.2-cp27-cp27m-manylinux1_i686.whl", hash = "sha256:6e6a84efb7856f5d760ee55cd2b446972cb7b835676065f6c4f694913ea8f8d9"}, - {file = "pysha3-1.0.2-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:f9046d59b3e72aa84f6dae83a040bd1184ebd7fef4e822d38186a8158c89e3cf"}, - {file = "pysha3-1.0.2-cp27-cp27m-win32.whl", hash = "sha256:9fdd28884c5d0b4edfed269b12badfa07f1c89dbc5c9c66dd279833894a9896b"}, - {file = "pysha3-1.0.2-cp27-cp27m-win_amd64.whl", hash = "sha256:41be70b06c8775a9e4d4eeb52f2f6a3f356f17539a54eac61f43a29e42fd453d"}, - {file = "pysha3-1.0.2-cp27-cp27mu-manylinux1_i686.whl", hash = "sha256:68c3a60a39f9179b263d29e221c1bd6e01353178b14323c39cc70593c30f21c5"}, - {file = "pysha3-1.0.2-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:59111c08b8f34495575d12e5f2ce3bafb98bea470bc81e70c8b6df99aef0dd2f"}, - {file = "pysha3-1.0.2-cp33-cp33m-win32.whl", hash = "sha256:571a246308a7b63f15f5aa9651f99cf30f2a6acba18eddf28f1510935968b603"}, - {file = "pysha3-1.0.2-cp33-cp33m-win_amd64.whl", hash = "sha256:93abd775dac570cb9951c4e423bcb2bc6303a9d1dc0dc2b7afa2dd401d195b24"}, - {file = "pysha3-1.0.2-cp34-cp34m-manylinux1_i686.whl", hash = "sha256:11a2ba7a2e1d9669d0052fc8fb30f5661caed5512586ecbeeaf6bf9478ab5c48"}, - {file = "pysha3-1.0.2-cp34-cp34m-manylinux1_x86_64.whl", hash = "sha256:5ec8da7c5c70a53b5fa99094af3ba8d343955b212bc346a0d25f6ff75853999f"}, - {file = "pysha3-1.0.2-cp34-cp34m-win32.whl", hash = "sha256:9c778fa8b161dc9348dc5cc361e94d54aa5ff18413788f4641f6600d4893a608"}, - {file = "pysha3-1.0.2-cp34-cp34m-win_amd64.whl", hash = "sha256:fd7e66999060d079e9c0e8893e78d8017dad4f59721f6fe0be6307cd32127a07"}, - {file = "pysha3-1.0.2-cp35-cp35m-manylinux1_i686.whl", hash = "sha256:827b308dc025efe9b6b7bae36c2e09ed0118a81f792d888548188e97b9bf9a3d"}, - {file = "pysha3-1.0.2-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:4416f16b0f1605c25f627966f76873e432971824778b369bd9ce1bb63d6566d9"}, - {file = "pysha3-1.0.2-cp35-cp35m-win32.whl", hash = "sha256:c93a2676e6588abcfaecb73eb14485c81c63b94fca2000a811a7b4fb5937b8e8"}, - {file = "pysha3-1.0.2-cp35-cp35m-win_amd64.whl", hash = "sha256:684cb01d87ed6ff466c135f1c83e7e4042d0fc668fa20619f581e6add1d38d77"}, - {file = "pysha3-1.0.2-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:386998ee83e313b6911327174e088021f9f2061cbfa1651b97629b761e9ef5c4"}, - {file = "pysha3-1.0.2-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:c7c2adcc43836223680ebdf91f1d3373543dc32747c182c8ca2e02d1b69ce030"}, - {file = "pysha3-1.0.2-cp36-cp36m-win32.whl", hash = "sha256:cd5c961b603bd2e6c2b5ef9976f3238a561c58569945d4165efb9b9383b050ef"}, - {file = "pysha3-1.0.2-cp36-cp36m-win_amd64.whl", hash = "sha256:0060a66be16665d90c432f55a0ba1f6480590cfb7d2ad389e688a399183474f0"}, - {file = "pysha3-1.0.2.tar.gz", hash = "sha256:fe988e73f2ce6d947220624f04d467faf05f1bbdbc64b0a201296bb3af92739e"}, -] - [[package]] name = "pytest" version = "7.3.0" diff --git a/pyproject.toml b/pyproject.toml index d0993845..3b430130 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -49,6 +49,7 @@ include = ["CHANGES.md", "docs/*", "docs/validators.1", "validators/py.typed"] [tool.poetry.dependencies] python = "^3.8" +eth-hash = "^0.5.2" [tool.poetry.group.docs] optional = true diff --git a/validators/crypto_addresses/eth_address.py b/validators/crypto_addresses/eth_address.py index e181b0b7..3a00def2 100644 --- a/validators/crypto_addresses/eth_address.py +++ b/validators/crypto_addresses/eth_address.py @@ -4,7 +4,7 @@ # standard import re -from sha3 import keccak_256 +from eth_hash.auto import keccak # local from validators.utils import validator @@ -13,7 +13,7 @@ def _validate_eth_checksum_address(addr: str): """Validate ETH type checksum address.""" addr = addr.replace("0x", "") - addr_hash = keccak_256(addr.lower().encode("ascii")).hexdigest() + addr_hash = keccak.new(addr.lower().encode("ascii")).digest().hex() if len(addr) != 40: return False From b40cb12b3f7cdb915f4efc3956d3a2bb13150fe8 Mon Sep 17 00:00:00 2001 From: Mehdi Samsami Date: Tue, 27 Jun 2023 09:36:18 +0330 Subject: [PATCH 18/21] use external tag --- validators/crypto_addresses/eth_address.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/validators/crypto_addresses/eth_address.py b/validators/crypto_addresses/eth_address.py index 3a00def2..0d578d55 100644 --- a/validators/crypto_addresses/eth_address.py +++ b/validators/crypto_addresses/eth_address.py @@ -1,7 +1,7 @@ """ETH Address.""" # -*- coding: utf-8 -*- -# standard +# external import re from eth_hash.auto import keccak From 802487f5e6dacbc7adddf34138a0130b2bbe3eda Mon Sep 17 00:00:00 2001 From: Mehdi Samsami Date: Tue, 27 Jun 2023 11:30:49 +0330 Subject: [PATCH 19/21] fix import tags --- validators/crypto_addresses/eth_address.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/validators/crypto_addresses/eth_address.py b/validators/crypto_addresses/eth_address.py index 0d578d55..8d50554b 100644 --- a/validators/crypto_addresses/eth_address.py +++ b/validators/crypto_addresses/eth_address.py @@ -1,9 +1,10 @@ """ETH Address.""" # -*- coding: utf-8 -*- -# external +# standard import re +# external from eth_hash.auto import keccak # local From c825de240e1c6cbcf2a862faeedb83b10c07313c Mon Sep 17 00:00:00 2001 From: Mehdi Samsami Date: Tue, 27 Jun 2023 11:54:25 +0330 Subject: [PATCH 20/21] add eth-hash backends dependency --- poetry.lock | 54 +++++++++++++++++++++++++++++++++++++++++++++++++- pyproject.toml | 2 +- 2 files changed, 54 insertions(+), 2 deletions(-) diff --git a/poetry.lock b/poetry.lock index 0d537cdb..d1466dc2 100644 --- a/poetry.lock +++ b/poetry.lock @@ -296,6 +296,17 @@ files = [ {file = "eth_hash-0.5.2-py3-none-any.whl", hash = "sha256:251f62f6579a1e247561679d78df37548bd5f59908da0b159982bf8293ad32f0"}, ] +[package.dependencies] +pycryptodome = {version = ">=3.6.6,<4", optional = true, markers = "extra == \"pycryptodome\""} + +[package.extras] +dev = ["black (>=23)", "build (>=0.9.0)", "bumpversion (>=0.5.3)", "flake8 (==6.0.0)", "flake8-bugbear (==23.3.23)", "ipython", "isort (>=5.10.1)", "mypy (==0.971)", "pydocstyle (>=6.0.0)", "pytest (>=7.0.0)", "pytest-watch (>=4.1.0)", "pytest-xdist (>=2.4.0)", "sphinx (>=6.0.0)", "sphinx-rtd-theme (>=1.0.0)", "towncrier (>=21,<22)", "tox (>=4.0.0)", "twine", "wheel"] +doc = ["sphinx (>=6.0.0)", "sphinx-rtd-theme (>=1.0.0)", "towncrier (>=21,<22)"] +lint = ["black (>=23)", "flake8 (==6.0.0)", "flake8-bugbear (==23.3.23)", "isort (>=5.10.1)", "mypy (==0.971)", "pydocstyle (>=6.0.0)"] +pycryptodome = ["pycryptodome (>=3.6.6,<4)"] +pysha3 = ["pysha3 (>=1.0.0,<2.0.0)", "safe-pysha3 (>=1.0.0)"] +test = ["pytest (>=7.0.0)", "pytest-xdist (>=2.4.0)"] + [[package]] name = "exceptiongroup" version = "1.1.1" @@ -983,6 +994,47 @@ files = [ {file = "pycodestyle-2.9.1.tar.gz", hash = "sha256:2c9607871d58c76354b697b42f5d57e1ada7d261c261efac224b664affdc5785"}, ] +[[package]] +name = "pycryptodome" +version = "3.18.0" +description = "Cryptographic library for Python" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" +files = [ + {file = "pycryptodome-3.18.0-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:d1497a8cd4728db0e0da3c304856cb37c0c4e3d0b36fcbabcc1600f18504fc54"}, + {file = "pycryptodome-3.18.0-cp27-cp27m-manylinux2010_i686.whl", hash = "sha256:928078c530da78ff08e10eb6cada6e0dff386bf3d9fa9871b4bbc9fbc1efe024"}, + {file = "pycryptodome-3.18.0-cp27-cp27m-manylinux2010_x86_64.whl", hash = "sha256:157c9b5ba5e21b375f052ca78152dd309a09ed04703fd3721dce3ff8ecced148"}, + {file = "pycryptodome-3.18.0-cp27-cp27m-manylinux2014_aarch64.whl", hash = "sha256:d20082bdac9218649f6abe0b885927be25a917e29ae0502eaf2b53f1233ce0c2"}, + {file = "pycryptodome-3.18.0-cp27-cp27m-musllinux_1_1_aarch64.whl", hash = "sha256:e8ad74044e5f5d2456c11ed4cfd3e34b8d4898c0cb201c4038fe41458a82ea27"}, + {file = "pycryptodome-3.18.0-cp27-cp27m-win32.whl", hash = "sha256:62a1e8847fabb5213ccde38915563140a5b338f0d0a0d363f996b51e4a6165cf"}, + {file = "pycryptodome-3.18.0-cp27-cp27m-win_amd64.whl", hash = "sha256:16bfd98dbe472c263ed2821284118d899c76968db1a6665ade0c46805e6b29a4"}, + {file = "pycryptodome-3.18.0-cp27-cp27mu-manylinux2010_i686.whl", hash = "sha256:7a3d22c8ee63de22336679e021c7f2386f7fc465477d59675caa0e5706387944"}, + {file = "pycryptodome-3.18.0-cp27-cp27mu-manylinux2010_x86_64.whl", hash = "sha256:78d863476e6bad2a592645072cc489bb90320972115d8995bcfbee2f8b209918"}, + {file = "pycryptodome-3.18.0-cp27-cp27mu-manylinux2014_aarch64.whl", hash = "sha256:b6a610f8bfe67eab980d6236fdc73bfcdae23c9ed5548192bb2d530e8a92780e"}, + {file = "pycryptodome-3.18.0-cp27-cp27mu-musllinux_1_1_aarch64.whl", hash = "sha256:422c89fd8df8a3bee09fb8d52aaa1e996120eafa565437392b781abec2a56e14"}, + {file = "pycryptodome-3.18.0-cp35-abi3-macosx_10_9_universal2.whl", hash = "sha256:9ad6f09f670c466aac94a40798e0e8d1ef2aa04589c29faa5b9b97566611d1d1"}, + {file = "pycryptodome-3.18.0-cp35-abi3-macosx_10_9_x86_64.whl", hash = "sha256:53aee6be8b9b6da25ccd9028caf17dcdce3604f2c7862f5167777b707fbfb6cb"}, + {file = "pycryptodome-3.18.0-cp35-abi3-manylinux2014_aarch64.whl", hash = "sha256:10da29526a2a927c7d64b8f34592f461d92ae55fc97981aab5bbcde8cb465bb6"}, + {file = "pycryptodome-3.18.0-cp35-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f21efb8438971aa16924790e1c3dba3a33164eb4000106a55baaed522c261acf"}, + {file = "pycryptodome-3.18.0-cp35-abi3-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4944defabe2ace4803f99543445c27dd1edbe86d7d4edb87b256476a91e9ffa4"}, + {file = "pycryptodome-3.18.0-cp35-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:51eae079ddb9c5f10376b4131be9589a6554f6fd84f7f655180937f611cd99a2"}, + {file = "pycryptodome-3.18.0-cp35-abi3-musllinux_1_1_i686.whl", hash = "sha256:83c75952dcf4a4cebaa850fa257d7a860644c70a7cd54262c237c9f2be26f76e"}, + {file = "pycryptodome-3.18.0-cp35-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:957b221d062d5752716923d14e0926f47670e95fead9d240fa4d4862214b9b2f"}, + {file = "pycryptodome-3.18.0-cp35-abi3-win32.whl", hash = "sha256:795bd1e4258a2c689c0b1f13ce9684fa0dd4c0e08680dcf597cf9516ed6bc0f3"}, + {file = "pycryptodome-3.18.0-cp35-abi3-win_amd64.whl", hash = "sha256:b1d9701d10303eec8d0bd33fa54d44e67b8be74ab449052a8372f12a66f93fb9"}, + {file = "pycryptodome-3.18.0-pp27-pypy_73-manylinux2010_x86_64.whl", hash = "sha256:cb1be4d5af7f355e7d41d36d8eec156ef1382a88638e8032215c215b82a4b8ec"}, + {file = "pycryptodome-3.18.0-pp27-pypy_73-win32.whl", hash = "sha256:fc0a73f4db1e31d4a6d71b672a48f3af458f548059aa05e83022d5f61aac9c08"}, + {file = "pycryptodome-3.18.0-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:f022a4fd2a5263a5c483a2bb165f9cb27f2be06f2f477113783efe3fe2ad887b"}, + {file = "pycryptodome-3.18.0-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:363dd6f21f848301c2dcdeb3c8ae5f0dee2286a5e952a0f04954b82076f23825"}, + {file = "pycryptodome-3.18.0-pp38-pypy38_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:12600268763e6fec3cefe4c2dcdf79bde08d0b6dc1813887e789e495cb9f3403"}, + {file = "pycryptodome-3.18.0-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:4604816adebd4faf8810782f137f8426bf45fee97d8427fa8e1e49ea78a52e2c"}, + {file = "pycryptodome-3.18.0-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:01489bbdf709d993f3058e2996f8f40fee3f0ea4d995002e5968965fa2fe89fb"}, + {file = "pycryptodome-3.18.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3811e31e1ac3069988f7a1c9ee7331b942e605dfc0f27330a9ea5997e965efb2"}, + {file = "pycryptodome-3.18.0-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6f4b967bb11baea9128ec88c3d02f55a3e338361f5e4934f5240afcb667fdaec"}, + {file = "pycryptodome-3.18.0-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:9c8eda4f260072f7dbe42f473906c659dcbadd5ae6159dfb49af4da1293ae380"}, + {file = "pycryptodome-3.18.0.tar.gz", hash = "sha256:c9adee653fc882d98956e33ca2c1fb582e23a8af7ac82fee75bd6113c55a0413"}, +] + [[package]] name = "pydocstyle" version = "6.3.0" @@ -1673,4 +1725,4 @@ testing = ["big-O", "flake8 (<5)", "jaraco.functools", "jaraco.itertools", "more [metadata] lock-version = "2.0" python-versions = "^3.8" -content-hash = "228af2ad6c7eccee9ea51a5667ef5b0cd5ae287fdc084ff8fb66ff9c4649ccb4" +content-hash = "228af2ad6c7eccee9ea51a5667ef5b0cd5ae287fdc084ff8fb66ff9c4649ccb4" \ No newline at end of file diff --git a/pyproject.toml b/pyproject.toml index 3b430130..4471913e 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -49,7 +49,7 @@ include = ["CHANGES.md", "docs/*", "docs/validators.1", "validators/py.typed"] [tool.poetry.dependencies] python = "^3.8" -eth-hash = "^0.5.2" +eth-hash = {extras = ["pycryptodome"], version = "^0.5.2"} [tool.poetry.group.docs] optional = true From 21d51f30be0eaa2b85412cfe7b91e4585badcf54 Mon Sep 17 00:00:00 2001 From: Mehdi Samsami Date: Tue, 27 Jun 2023 12:00:15 +0330 Subject: [PATCH 21/21] reformat using black --- validators/crypto_addresses/__init__.py | 2 +- validators/crypto_addresses/eth_address.py | 12 ++++++------ 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/validators/crypto_addresses/__init__.py b/validators/crypto_addresses/__init__.py index 2b62a3bf..1c9bd5c6 100644 --- a/validators/crypto_addresses/__init__.py +++ b/validators/crypto_addresses/__init__.py @@ -6,4 +6,4 @@ # local from .eth_address import eth_address -__all__ = ("eth_address", ) +__all__ = ("eth_address",) diff --git a/validators/crypto_addresses/eth_address.py b/validators/crypto_addresses/eth_address.py index 8d50554b..80aaed41 100644 --- a/validators/crypto_addresses/eth_address.py +++ b/validators/crypto_addresses/eth_address.py @@ -20,8 +20,9 @@ def _validate_eth_checksum_address(addr: str): return False for i in range(0, 40): - if ((int(addr_hash[i], 16) > 7 and addr[i].upper() != addr[i]) or - (int(addr_hash[i], 16) <= 7 and addr[i].lower() != addr[i])): + if (int(addr_hash[i], 16) > 7 and addr[i].upper() != addr[i]) or ( + int(addr_hash[i], 16) <= 7 and addr[i].lower() != addr[i] + ): return False return True @@ -52,7 +53,6 @@ def eth_address(value: str, /): if not value: return False - return ( - re.compile(r"^0x[0-9a-f]{40}$|^0x[0-9A-F]{40}$").match(value) or - _validate_eth_checksum_address(value) - ) + return re.compile(r"^0x[0-9a-f]{40}$|^0x[0-9A-F]{40}$").match( + value + ) or _validate_eth_checksum_address(value)