Skip to content

Commit bb4a780

Browse files
authored
Make eth-keys optional (#392)
1 parent dd209c7 commit bb4a780

File tree

10 files changed

+515
-361
lines changed

10 files changed

+515
-361
lines changed

.coveragerc

-6
This file was deleted.

.github/workflows/ci.yml

+2-1
Original file line numberDiff line numberDiff line change
@@ -28,14 +28,15 @@ jobs:
2828
- run: brew install automake
2929
if: matrix.os == 'macos-latest'
3030

31-
- run: poetry install --with test
31+
- run: poetry install --with test -E eth
3232

3333
- name: Run test
3434
run: poetry run pytest -s --cov=ecies tests --cov-report xml
3535

3636
- run: ./scripts/ci.sh
3737

3838
- uses: codecov/codecov-action@v4
39+
if: matrix.os == 'ubuntu-latest' && matrix.python-version == '3.13'
3940
with:
4041
token: ${{ secrets.CODECOV_TOKEN }}
4142

ecies/__init__.py

+9-6
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
from .config import ECIES_CONFIG, Config
66
from .utils import (
7+
compat_eth_public_key,
78
decapsulate,
89
encapsulate,
910
generate_key,
@@ -16,7 +17,9 @@
1617
__all__ = ["encrypt", "decrypt", "ECIES_CONFIG"]
1718

1819

19-
def encrypt(receiver_pk: Union[str, bytes], msg: bytes, config: Config = ECIES_CONFIG) -> bytes:
20+
def encrypt(
21+
receiver_pk: Union[str, bytes], msg: bytes, config: Config = ECIES_CONFIG
22+
) -> bytes:
2023
"""
2124
Encrypt with receiver's secp256k1 public key
2225
@@ -35,21 +38,21 @@ def encrypt(receiver_pk: Union[str, bytes], msg: bytes, config: Config = ECIES_C
3538
if isinstance(receiver_pk, str):
3639
pk = hex2pk(receiver_pk)
3740
elif isinstance(receiver_pk, bytes):
38-
pk = PublicKey(receiver_pk)
41+
pk = PublicKey(compat_eth_public_key(receiver_pk))
3942
else:
4043
raise TypeError("Invalid public key type")
4144

4245
ephemeral_sk = generate_key()
43-
ephemeral_pk = ephemeral_sk.public_key.format(
44-
config.is_ephemeral_key_compressed
45-
)
46+
ephemeral_pk = ephemeral_sk.public_key.format(config.is_ephemeral_key_compressed)
4647

4748
sym_key = encapsulate(ephemeral_sk, pk, config)
4849
encrypted = sym_encrypt(sym_key, msg, config)
4950
return ephemeral_pk + encrypted
5051

5152

52-
def decrypt(receiver_sk: Union[str, bytes], msg: bytes, config: Config = ECIES_CONFIG) -> bytes:
53+
def decrypt(
54+
receiver_sk: Union[str, bytes], msg: bytes, config: Config = ECIES_CONFIG
55+
) -> bytes:
5356
"""
5457
Decrypt with receiver's secp256k1 private key
5558

ecies/__main__.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -69,12 +69,12 @@ def main():
6969
args = parser.parse_args()
7070
if args.generate:
7171
k = generate_eth_key()
72-
sk, pub, addr = (
72+
sk, pk, addr = (
7373
k.to_hex(),
7474
k.public_key.to_hex(),
7575
k.public_key.to_checksum_address(),
7676
)
77-
print("Private: {}\nPublic: {}\nAddress: {}".format(sk, pub, addr))
77+
print("Private: {}\nPublic: {}\nAddress: {}".format(sk, pk, addr))
7878
return
7979

8080
if args.encrypt == args.decrypt:

ecies/utils/__init__.py

+2
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
from .elliptic import (
2+
compat_eth_public_key,
23
decapsulate,
34
encapsulate,
45
generate_eth_key,
@@ -20,4 +21,5 @@
2021
"hex2pk",
2122
"decapsulate",
2223
"encapsulate",
24+
"compat_eth_public_key",
2325
]

ecies/utils/elliptic.py

+14-25
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
from coincurve import PrivateKey, PublicKey
22
from coincurve.utils import get_valid_secret
3-
from eth_keys import keys
43

54
from ..config import ECIES_CONFIG, Config
65
from .hex import decode_hex
@@ -30,8 +29,9 @@ def generate_eth_key():
3029
eth_keys.keys.PrivateKey
3130
An ethereum key
3231
33-
>>> k = generate_eth_key()
3432
"""
33+
from eth_keys import keys
34+
3535
return keys.PrivateKey(get_valid_secret())
3636

3737

@@ -51,23 +51,14 @@ def hex2pk(pk_hex: str) -> PublicKey:
5151
coincurve.PublicKey
5252
A secp256k1 public key
5353
54-
>>> from ecies.utils import sha256
55-
>>> data = b'0' * 32
56-
>>> data_hash = sha256(data)
57-
>>> eth_sk = generate_eth_key()
58-
>>> cc_sk = hex2sk(eth_sk.to_hex())
59-
>>> eth_sk.sign_msg_hash(data_hash).to_bytes() == cc_sk.sign_recoverable(data)
60-
True
61-
>>> pk_hex = eth_sk.public_key.to_hex()
62-
>>> computed_pk = hex2pk(pk_hex)
63-
>>> computed_pk == cc_sk.public_key
64-
True
6554
"""
66-
uncompressed = decode_hex(pk_hex)
67-
if len(uncompressed) == 64: # eth public key format
68-
uncompressed = b"\x04" + uncompressed
55+
return PublicKey(compat_eth_public_key(decode_hex(pk_hex)))
56+
6957

70-
return PublicKey(uncompressed)
58+
def compat_eth_public_key(data: bytes):
59+
if len(data) == 64: # eth public key format
60+
data = b"\x04" + data
61+
return data
7162

7263

7364
def hex2sk(sk_hex: str) -> PrivateKey:
@@ -84,18 +75,14 @@ def hex2sk(sk_hex: str) -> PrivateKey:
8475
coincurve.PrivateKey
8576
A secp256k1 private key
8677
87-
>>> k = generate_eth_key()
88-
>>> sk_hex = k.to_hex()
89-
>>> pk_hex = k.public_key.to_hex()
90-
>>> computed_sk = hex2sk(sk_hex)
91-
>>> computed_sk.to_int() == int(k.to_hex(), 16)
92-
True
9378
"""
9479
return PrivateKey(decode_hex(sk_hex))
9580

9681

9782
# private below
98-
def encapsulate(private_key: PrivateKey, peer_public_key: PublicKey, config: Config = ECIES_CONFIG) -> bytes:
83+
def encapsulate(
84+
private_key: PrivateKey, peer_public_key: PublicKey, config: Config = ECIES_CONFIG
85+
) -> bytes:
9986
is_compressed = config.is_hkdf_key_compressed
10087
shared_point = peer_public_key.multiply(private_key.secret)
10188
master = private_key.public_key.format(is_compressed) + shared_point.format(
@@ -104,7 +91,9 @@ def encapsulate(private_key: PrivateKey, peer_public_key: PublicKey, config: Con
10491
return derive_key(master)
10592

10693

107-
def decapsulate(public_key: PublicKey, peer_private_key: PrivateKey, config: Config = ECIES_CONFIG) -> bytes:
94+
def decapsulate(
95+
public_key: PublicKey, peer_private_key: PrivateKey, config: Config = ECIES_CONFIG
96+
) -> bytes:
10897
is_compressed = config.is_hkdf_key_compressed
10998
shared_point = public_key.multiply(peer_private_key.secret)
11099
master = public_key.format(is_compressed) + shared_point.format(is_compressed)

0 commit comments

Comments
 (0)