create account

Ethereum Classic Elliptic Curve Integrated Encryption Scheme by cseberino

View this thread on: hive.blogpeakd.comecency.com
· @cseberino · (edited)
Ethereum Classic Elliptic Curve Integrated Encryption Scheme
![](https://i.imgur.com/NKaeoya.jpg)

Ethereum Classic (ETC) uses a multistep protocol to send private messages between network nodes. This is referred to as the Elliptic Curve Integrated Encryption Scheme (ECIES).

# Procedure

![](https://i.imgur.com/MlTUJ1C.png)

The first ETC ECIES step is to create an “ephemeral” private and public key pair. The second step is to create a shared secret by multiplying the ephemeral private key and the public key of the *other* node. See the [Elliptic Curve Diffie Hellman algorithm](https://steemit.com/ethereum/@cseberino/how-ethereum-classic-nodes-create-shared-secrets) for further details on this. The third step is to use this shared secret to derive an AES (Advanced Encryption Standard) key and an [HMAC](https://medium.com/@cseberino/ethereum-classic-hmacs-d9e987b5465c) (hash based message authentication code) secret using the ETC [key derivation function](https://medium.com/@cseberino/the-ethereum-classic-key-derivation-function-fa1819da742). The fourth step is to encrypt the message which involves creating a random “initialization vector”. The fifth step is to create an HMAC for the initialization vector and the encrypted message. The last step is to send the following components to the other node:

```
1. ephemeral public key
2. initialization vector
3. encrypted message
4. HMAC
```
<br>ETC uses AES in “counter mode” with 128 bit keys. The initialization vector and its derivatives are encrypted then exclusive OR’d with the message to produce the encrypted version.

# Implentation

An example Python ETC ECIES implementation is provided below which uses the Python Cryptography Toolkit (pycrypto) package:

```
#!/usr/bin/env python3

import Crypto.Cipher.AES
import Crypto.Util.Counter
import hashlib
import random

N  = 115792089237316195423570985008687907852837564279074904382605163141518161494337
P  = 115792089237316195423570985008687907853269984665640564039457584007908834671663
Gx = 55066263022277343669578718895168534326250603453777594175500187360389116729240
Gy = 32670510020758816978083085130507043184471273380659243275938904335757337482424

PUBLIC_KEY_SIZE   = 64
SHA256_BLOCK_SIZE = 64
AES_KEY_SIZE      = 16
AES_BLOCK_SIZE    = 16
HMAC_SIZE         = 32
NUM_BITS_PER_BYTE = 8

def invert(number, modulus):
        """
        Finds the inverses of natural numbers.
        """

        result = 1
        power  = number
        for e in bin(modulus - 2)[2:][::-1]:
                if int(e):
                        result = (result * power) % modulus
                power = (power ** 2) % modulus

        return result

def add(pair_1, pair_2):
        """
        Finds the sums of two pairs of natural numbers.
        """

        if   pair_1 == [0, 0]:
                result = pair_2
        elif pair_2 == [0, 0]:
                result = pair_1
        else:
                if pair_1 == pair_2:
                        temp = 3 * pair_1[0] ** 2
                        temp = (temp * invert(2 * pair_1[1], P)) % P
                else:
                        temp = pair_2[1] - pair_1[1]
                        temp = (temp * invert(pair_2[0] - pair_1[0], P)) % P
                result = (temp ** 2 - pair_1[0]  - pair_2[0]) % P
                result = [result, (temp * (pair_1[0] - result) - pair_1[1]) % P]

        return result

def multiply(number, pair):
        """
        Finds the products of natural numbers and pairs of natural numbers.
        """

        result = [0, 0]
        power  = pair[:]
        for e in bin(number)[2:][::-1]:
                if int(e):
                        result = add(result, power)
                power = add(power, power)

        return result

def make_private_key():
        """
        Creates random private keys.
        """

        return random.randint(1, N)

def get_public_key(private_key):
        """
        Calculates public keys from private keys.
        """

        return multiply(private_key, (Gx, Gy))

def get_shared_secret(private_key, public_key):
        """
        Calculates shared secrets from public and private keys.
        """

        return multiply(private_key, public_key)[0]

def kdf(secret):
        """
        Implements the key derivation function.
        """

        secret = secret.to_bytes(PUBLIC_KEY_SIZE // 2, "big")
        key    = hashlib.sha256(b"\x00\x00\x00\x01" + secret).digest()

        return key

def hmac(secret, message):
        """
        Calculates hash based message authenticaion codes (HMACs).
        """

        secret = hashlib.sha256(secret).digest()
        secret = secret.ljust(SHA256_BLOCK_SIZE, b"\x00")
        ipad   = SHA256_BLOCK_SIZE * bytes.fromhex("36")
        opad   = SHA256_BLOCK_SIZE * bytes.fromhex("5c")
        key_1  = bytes([x ^ y for x, y in zip(secret, ipad)])
        key_2  = bytes([x ^ y for x, y in zip(secret, opad)])
        hash_  = hashlib.sha256(key_1 + message).digest()
        hmac_  = hashlib.sha256(key_2 +   hash_).digest()

        return hmac_

def aes_ctr_encrypt(message, key, iv):
        """
        Encrypts messages using AES in counter mode.
        """

        iv      = int.from_bytes(iv, 'big')
        counter = Crypto.Util.Counter.new(AES_KEY_SIZE * NUM_BITS_PER_BYTE,
                                          initial_value = iv)
        aes_ctr = Crypto.Cipher.AES.new(key,
                                        Crypto.Cipher.AES.MODE_CTR,
                                        counter = counter)

        return aes_ctr.encrypt(message)

def ecies_send(message, receiv_pub_key):
        """
        Creates the ECIES byte string to send a message.
        """

        eph_priv_key   = make_private_key()
        eph_pub_key    = get_public_key(eph_priv_key)
        eph_pub_key[0] = eph_pub_key[0].to_bytes(PUBLIC_KEY_SIZE // 2, "big")
        eph_pub_key[1] = eph_pub_key[1].to_bytes(PUBLIC_KEY_SIZE // 2, "big")
        eph_pub_key    = b"\x04" + eph_pub_key[0] + eph_pub_key[1]
        shared_secret  = get_shared_secret(eph_priv_key, receiv_pub_key)
        kdf_key        = kdf(shared_secret)
        aes_key        = kdf_key[:AES_KEY_SIZE]
        hmac_secret    = kdf_key[AES_KEY_SIZE:]
        iv             = random.getrandbits(AES_BLOCK_SIZE * NUM_BITS_PER_BYTE)
        iv             = iv.to_bytes(AES_BLOCK_SIZE, "big")
        ciphertext     = aes_ctr_encrypt(message, aes_key, iv)
        hmac_          = hmac(hmac_secret, iv + ciphertext)

        return eph_pub_key + iv + ciphertext + hmac_

def ecies_receive(received, receiv_priv_key):
        """
        Extracts the message from an ECIES byte string.
        """

        eph_pub_key   = received[:PUBLIC_KEY_SIZE + 1]
        eph_pub_key   = [eph_pub_key[1:][:PUBLIC_KEY_SIZE // 2],
                         eph_pub_key[1:][PUBLIC_KEY_SIZE // 2:]]
        eph_pub_key   = [int.from_bytes(e, "big") for e in eph_pub_key]
        iv_index      = PUBLIC_KEY_SIZE + 1
        iv            = received[iv_index:iv_index + AES_BLOCK_SIZE]
        ciphertext    = received[iv_index + AES_BLOCK_SIZE:-HMAC_SIZE]
        hmac_         = received[-HMAC_SIZE:]
        shared_secret = get_shared_secret(receiv_priv_key, eph_pub_key)
        kdf_key       = kdf(shared_secret)
        aes_key       = kdf_key[:AES_KEY_SIZE]
        hmac_secret   = kdf_key[AES_KEY_SIZE:]
        message       = b""
        if hmac(hmac_secret, iv + ciphertext) == hmac_:
                message += aes_ctr_encrypt(ciphertext, aes_key, iv)

        return message
```
<br>Here is an example of its usage in a Python shell:

```
>>> receiv_priv_key = make_private_key()

>>> receiv_priv_key
65220784268995169636487104126103071511455089901114970914953057647529653418334

>>> receiv_pub_key = get_public_key(receiv_priv_key)

>>> receiv_pub_key
[27571019357111177175074932706008560366518621617269680530116383769747086735803, 6491692355663560906178933703971523490656680637639444902444063317701241768362]

>>> message = b"This is the message."

>>> sent = ecies_send(message, receiv_pub_key)

>>> sent
b"\x04\xde\x02\x8a\x1b\x9er\x99s\xc8\xe5\x08m\xd3\xfa@\xc6,\x04\xe6%\x9e\xd3Y\xc1k\xc1X\x9c\xef\xfb^\x86K\xbb\xef\xb6]\xbc5\xec\rC|\xc7\xc2\xf5\x16\xa4s%_x7\xd64W\xb2<\x18\x03#t\xc4S\x16Z\xeb>j\x1f=\xd8\xb5_\x91v\xf4'\xe9\x88\xb5\x0b\x83\xedr\xd5`\xd8\x9e\x06`\xfc\xa1\xd6\xf8[~\x01WwT[2\x08\xd3\x11\xf3v\xb2\\\xd2\xc7\x87\t\xa0J\xc7\x17\xef\xd5\xedt\xf4\xcave\x02\xf9\xed\xdf\x95\x82"

>>> ecies_receive(sent, receiv_priv_key)
b'This is the message.'
```

# Feedback

Feel free to leave any comments or questions below. You can also contact me by email at cs@etcplanet.org or by clicking any of these icons:

[![](https://cdn-images-1.medium.com/max/1600/0*eoFC6QOWZ--bCngK.png)](https://twitter.com/chris_seberino)

[![](https://cdn-images-1.medium.com/max/1600/0*i3CwTFEKUnKYHMf0.png)](https://www.facebook.com/cseberino)

[![](https://cdn-images-1.medium.com/max/1600/0*HQj6HSHxE7pkIBjk.png)](https://www.linkedin.com/in/christian-seberino-776897110/)

# Acknowledgements

I would like to thank IOHK (Input Output Hong Kong) for funding this effort.

# License

[![](https://cdn-images-1.medium.com/max/1600/0*hocpUZXBcjzNJeQ2.png)](https://creativecommons.org/licenses/by-sa/4.0/)

This work is licensed under the Creative Commons Attribution ShareAlike 4.0 International License.
👍  
properties (23)
authorcseberino
permlinkethereum-classic-elliptic-curve-integrated-encryption-scheme
categoryethereum
json_metadata{"tags":["ethereum","ethereumclassic","blockchain","eth","etc"],"image":["https://i.imgur.com/NKaeoya.jpg","https://i.imgur.com/MlTUJ1C.png","https://cdn-images-1.medium.com/max/1600/0*eoFC6QOWZ--bCngK.png","https://cdn-images-1.medium.com/max/1600/0*i3CwTFEKUnKYHMf0.png","https://cdn-images-1.medium.com/max/1600/0*HQj6HSHxE7pkIBjk.png","https://cdn-images-1.medium.com/max/1600/0*hocpUZXBcjzNJeQ2.png"],"app":"steemit/0.1","format":"markdown","links":["https://steemit.com/ethereum/@cseberino/how-ethereum-classic-nodes-create-shared-secrets","https://medium.com/@cseberino/ethereum-classic-hmacs-d9e987b5465c","https://medium.com/@cseberino/the-ethereum-classic-key-derivation-function-fa1819da742","https://twitter.com/chris_seberino","https://www.facebook.com/cseberino","https://www.linkedin.com/in/christian-seberino-776897110/","https://creativecommons.org/licenses/by-sa/4.0/"]}
created2019-07-25 19:43:18
last_update2019-07-26 15:56:48
depth0
children1
last_payout2019-08-01 19:43:18
cashout_time1969-12-31 23:59:59
total_payout_value0.000 HBD
curator_payout_value0.000 HBD
pending_payout_value0.000 HBD
promoted0.000 HBD
body_length9,313
author_reputation5,161,857,859,658
root_title"Ethereum Classic Elliptic Curve Integrated Encryption Scheme"
beneficiaries[]
max_accepted_payout1,000,000.000 HBD
percent_hbd10,000
post_id88,740,709
net_rshares954,235,572
author_curate_reward""
vote details (1)
@steemitboard ·
Congratulations @cseberino! You received a personal award!

<table><tr><td>https://steemitimages.com/70x70/http://steemitboard.com/@cseberino/birthday3.png</td><td>Happy Birthday! - You are on the Steem blockchain for 3 years!</td></tr></table>

<sub>_You can view [your badges on your Steem Board](https://steemitboard.com/@cseberino) and compare to others on the [Steem Ranking](https://steemitboard.com/ranking/index.php?name=cseberino)_</sub>


###### [Vote for @Steemitboard as a witness](https://v2.steemconnect.com/sign/account-witness-vote?witness=steemitboard&approve=1) to get one more award and increased upvotes!
properties (22)
authorsteemitboard
permlinksteemitboard-notify-cseberino-20191003t215000000z
categoryethereum
json_metadata{"image":["https://steemitboard.com/img/notify.png"]}
created2019-10-03 21:50:00
last_update2019-10-03 21:50:00
depth1
children0
last_payout2019-10-10 21:50:00
cashout_time1969-12-31 23:59:59
total_payout_value0.000 HBD
curator_payout_value0.000 HBD
pending_payout_value0.000 HBD
promoted0.000 HBD
body_length624
author_reputation38,975,615,169,260
root_title"Ethereum Classic Elliptic Curve Integrated Encryption Scheme"
beneficiaries[]
max_accepted_payout1,000,000.000 HBD
percent_hbd10,000
post_id91,201,873
net_rshares0