Skip to content

Commit

Permalink
Merge pull request #16 from lc6chang/dev
Browse files Browse the repository at this point in the history
Add ElGamal.encrypt_point and ElGamal.decrypt_point
  • Loading branch information
lc6chang authored Mar 14, 2021
2 parents 543140e + b074a0c commit 55ee2e8
Show file tree
Hide file tree
Showing 4 changed files with 46 additions and 14 deletions.
9 changes: 6 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ This is a Python package for ECC and ElGamal elliptic curve encryption.

## Warning

This project only aims to help you learn and understand what is ECC and how the algorithm works. **Do not use it directly in production environment!**
This project only aims to help you learn and understand what is ECC and how the algorithm works. **Do not use it directly in the production environment!**

Some cons: The operations of curve points are just implemented in a common way. We don't implement them using [Jacobian Coordinates](https://en.wikibooks.org/wiki/Cryptography/Prime_Curve/Jacobian_Coordinates). Also, we implement them in pure Python. It will be slower than C.

Expand Down Expand Up @@ -42,14 +42,17 @@ from ecc.cipher import ElGamal


# Plaintext
plain_text = b"This-is-test-plaintext"
plaintext = b"I am plaintext."
# Generate key pair
pri_key, pub_key = gen_keypair(Curve25519)
# Encrypt using ElGamal algorithm
cipher_elg = ElGamal(Curve25519)
C1, C2 = cipher_elg.encrypt(plain_text, pub_key)
C1, C2 = cipher_elg.encrypt(plaintext, pub_key)
# Decrypt
new_plaintext = cipher_elg.decrypt(pri_key, C1, C2)

print(new_plaintext == plaintext)
# >> True
```

## Common elliptic curve
Expand Down
26 changes: 21 additions & 5 deletions ecc/cipher.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,27 @@ class ElGamal:

def encrypt(self, plaintext: bytes, public_key: Point,
randfunc: Callable = None) -> Tuple[Point, Point]:
return self.encrypt_bytes(plaintext, public_key, randfunc)

def decrypt(self, private_key: int, C1: Point, C2: Point) -> bytes:
return self.decrypt_bytes(private_key, C1, C2)

def encrypt_bytes(self, plaintext: bytes, public_key: Point,
randfunc: Callable = None) -> Tuple[Point, Point]:
# Encode plaintext into a curve point
M = self.curve.encode_point(plaintext)
return self.encrypt_point(M, public_key, randfunc)

def decrypt_bytes(self, private_key: int, C1: Point, C2: Point) -> bytes:
M = self.decrypt_point(private_key, C1, C2)
return self.curve.decode_point(M)

def encrypt_point(self, plaintext: Point, public_key: Point,
randfunc: Callable = None) -> Tuple[Point, Point]:
randfunc = randfunc or urandom
# Base point
# Base point G
G = self.curve.G
# Encode plaintext into curve point
M = self.curve.encode_point(plaintext)
M = plaintext

random.seed(randfunc(1024))
k = random.randint(1, self.curve.n)
Expand All @@ -25,6 +41,6 @@ def encrypt(self, plaintext: bytes, public_key: Point,
C2 = M + k * public_key
return C1, C2

def decrypt(self, private_key: int, C1: Point, C2: Point):
def decrypt_point(self, private_key: int, C1: Point, C2: Point) -> Point:
M = C2 + (self.curve.n - private_key) * C1
return self.curve.decode_point(M)
return M
5 changes: 3 additions & 2 deletions setup.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
from setuptools import setup, find_namespace_packages

from ecc import __version__

dependencies = [
"dataclasses"
"dataclasses",
]

setup(
name="ecc-pycrypto",
author="ChangLiu",
author="lc6chang",
author_email="[email protected]",
version=__version__,
packages=find_namespace_packages(),
Expand Down
20 changes: 16 additions & 4 deletions tests/test_cipher.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@


CURVES = [P256, secp256k1, Curve25519, M383, E222, E382]
PLAIN_TEXT = b"This is a plain text."
PLAINTEXT = b"I am plaintext."


class ElGamalTestCase(unittest.TestCase):
Expand All @@ -17,6 +17,18 @@ def test_encrypt_and_decrypt(self):
with self.subTest(curve=curve):
pri_key, pub_key = gen_keypair(curve)
cipher_elg = ElGamal(curve)
C1, C2 = cipher_elg.encrypt(PLAIN_TEXT, pub_key)
plain_text = cipher_elg.decrypt(pri_key, C1, C2)
self.assertEqual(plain_text, PLAIN_TEXT)
C1, C2 = cipher_elg.encrypt(PLAINTEXT, pub_key)
plaintext = cipher_elg.decrypt(pri_key, C1, C2)
self.assertEqual(plaintext, PLAINTEXT)

def test_additive_homomorphism_encryption(self):
for curve in CURVES:
with self.subTest(curve=curve):
pri_key, pub_key = gen_keypair(curve)
cipher_elg = ElGamal(curve)
plaintext1 = curve.G * 123
plaintext2 = curve.G * 456
C1, C2 = cipher_elg.encrypt_point(plaintext1, pub_key)
C3, C4 = cipher_elg.encrypt_point(plaintext2, pub_key)
plaintext = cipher_elg.decrypt_point(pri_key, C1 + C3, C2 + C4)
self.assertEqual(plaintext, plaintext1 + plaintext2)

0 comments on commit 55ee2e8

Please sign in to comment.