Introduction

Interactions with the Ethereum Classic (ETC) system depend on special numbers referred to as public keys and private keys. Private keys are used to transfer funds, install programs, and, run programs. These numbers must be kept secret at all times. Public keys are used to confirm knowledge of private keys without their disclosure. Public keys also provide a means of identifying accounts.

Details

Private keys are 32 byte numbers between 1 and

115792089237316195423570985008687907852837564279074904382605163141518161494336

inclusive. People randomly select them. Some may be concerned that two people might unintentionally select the same private key. The odds of that happening are vanishingly small. In fact, the number of possible private keys is approximately equal to the number of atoms in the entire universe!

Public keys are 64 byte numbers derived from private keys using an odd type of arithmetic with respect to pairs of numbers. Here is a Python script that calculates public keys from private keys:

#!/usr/bin/env python3 """ Calculates ETC public keys from ETC private keys. Usage: etc_pub_key <private key> """ import random import sys A = 0 N = 0xfffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141 P = 0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f GX = 0x79be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798 GY = 0x483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8 HEXADECIMAL = 16 NUM_FORMAT = "{{:0{}x}}".format(len(hex(P)[2:])) def inverse(number): """ Inverts a number. """ inverse = 1 power = number for e in bin(P - 2)[2:][::-1]: if int(e): inverse = (inverse * power) % P power = (power ** 2) % P return inverse def add(pair_1, pair_2): """ Adds two pairs. """ if pair_1 == "identity": sum_ = pair_2 elif pair_2 == "identity": sum_ = pair_1 else: if pair_1 == pair_2: numer = 3 * pair_1[0] ** 2 + A lambda_ = (numer * inverse(2 * pair_1[1])) % P else: numer = pair_2[1] - pair_1[1] denom = pair_2[0] - pair_1[0] lambda_ = (numer * inverse(denom)) % P x = (lambda_ ** 2 - pair_1[0] - pair_2[0]) % P y = (lambda_ * (pair_1[0] - x) - pair_1[1]) % P sum_ = (x, y) return sum_ def multiply(number, pair): """ Multiplies a pair by a number. """ product = "identity" power = pair[:] for e in bin(number)[2:][::-1]: if int(e): product = add(power, product) power = add(power, power) return product def convert(pair): """ Converts pairs to numbers by concatenating the elements. """ return int("".join([NUM_FORMAT.format(e) for e in pair]), HEXADECIMAL) print(convert(multiply(int(sys.argv[1]), (GX, GY))))

The reason for this convoluted process is so that private keys cannot be derived from public keys. If you want to learn more, investigate elliptic curve cryptography. The reason for this name is that historically it followed from calculations of the arc lengths of ellipses.

Miscellany

Addresses

The first 20 bytes of Keccak 256 hashes of public keys are referred to as account addresses. These are most often used to identify accounts rather than public keys. Interestingly, public keys cannot be determined solely from addresses.

Here is a Python script that calculates addresses from public keys. It requires the PySHA3 package. Addresses are typically expressed in hexadecimal notation and that convention is followed in this script:

#!/usr/bin/env python3 """ Calculates ETC addresses from ETC public keys. Usage: etc_address <public key> """ import sha3 import binascii import sys N_ADDRESS_BYTES = 20 N_PUB_KEY_BYTES = 64 public_key = (int(sys.argv[1])).to_bytes(N_PUB_KEY_BYTES, byteorder = "big") print(sha3.keccak_256(public_key).hexdigest()[-2 * N_ADDRESS_BYTES:])

Signatures

Private keys provide a way to effectively sign transactions. For this, ETC uses the Elliptic Curve Digital Signature Algorithm (ECDSA). The basic idea is to create sets of numbers, corresponding to transactions, that can only be generated by the sending account private keys. This is analogous to handwritten signatures that can only be generated by the corresponding hands.

Programs

Programs, or smart contracts, do not have their own public and private keys. Therefore, programs cannot digitally sign transactions. Furthermore, program account addresses must be selected by some other means.

Example

Here is a slightly edited session, on a Linux computer, that calculates a public key and address with regards to a random private key. It uses the aforementioned scripts saved in files called etc_pub_key and etc_address respectively:

% PRIVATE_KEY="92788259381212812445638172234843282167646237087212249687358593145563035518424" % PUBLIC_KEY=`etc_pub_key $PRIVATE_KEY` % ADDRESS=`etc_address $PUBLIC_KEY` % echo $PRIVATE_KEY 92788259381212812445638172234843282167646237087212249687358593145563035518424 % echo $PUBLIC_KEY 9808854183897174607002157792089896992612613490844656534725423301978228163634425857099752732031947328803605451685330420628756154476771607661633738743568351 % echo $ADDRESS 89b44e4d3c81ede05d0f5de8d1a68f754d73d997

Conclusion

Public and private keys are widely used in ETC and in other technologies. Therefore, I hope this has been enlightening.

Feedback

Feel free to leave any comments or questions below. You can also contact me by clicking any of these icons:

Acknowledgements

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

License

This work is licensed under the Creative Commons Attribution ShareAlike 4.0 International License.