Project Link: https://github.com/BerkeleyBlockchain/Cryptography
Python, Pytest
This was my first semester internal project for Blockchain at Berkeley’s Education Department.
The goal of the project was to learn about and implement the most common cryptographic schemes, which included RSA, Shamir’s secret sharing, and ECDSA.
Here’s a basic outline of what we implemented.
gcd(x, y)
gcd(x, y) == 1
gcd(x, y) = gcd(y, x mod y)
is_prime(x)
encrypt(keypair, unencrypted)
E(x) = x^e mod pq
decrypt(keypair, encrypted)
d = e^-1 mod (p-1)(q-1)
: D(y) = y^d mod pq
Below is an example of how you could use the script:
rsa = RSA(name='Justin')
msg = 'Hello, world!'
encrypted = rsa.encrypt(msg)
decrypted = rsa.decrypt(encrypted)
print(decrypted) # Hello, world!
A secret-sharing scheme tries to split up some secret s
among n
individuals, where k
individuals need
to come together to access s
. Any fewer will result in a garbage answer and force a brute-force computation
to try finding the secret.
To do this, we use the property that an (k-1)
-degree polynomial is defined uniquely on k
points. We generate
a random polynomial f(x)
that satisfies f(0) = s
. If we evaluate the polynomial at 0, then we get the secret.
This polynomial will be degree (k-1)
, and each share will be a point (i, f(i))
on the polynomial. Hand out
n
unique shares to the n
individuals. k
individuals can come together to recreate the polynomial f(x)
by using Lagrange interpolation. Otherwise, the polynomial cannot be uniquely determined, so f(0)
of the
“recovered” polynomial could be any value.
Below is an outline of what we implemented.
lagrange_interpolation
(n-1)
-degree polynomial that is uniquely defined on n
points, in a mod field.div_mod
extended_GCD
generate_random_shares
generate_polynomial
f
such that f(0) = secret
.recover_secret
lagrange_interpolation
ECDSA stands for Elliptic Cryptography Digital Signature Algorithm. We implemented a basic elliptic curve cryptography scheme, which is used in Bitcoin to generate public keys.
Take a look at what a Bitcoin address generation script looks like (don’t use this private key!!):
from curve import Curve, FiniteCurve
from random import randrange
import hashlib
from hashlib import sha256
import base58check
# Params for secp256-k1 (Curve that Bitcoin uses)
# http://www.secg.org/sec2-v2.pdf
_a = 0x0000000000000000000000000000000000000000000000000000000000000000
_b = 0x0000000000000000000000000000000000000000000000000000000000000007
_p = 0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f
_Gx = 0x79be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798
_Gy = 0x483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8
_n = 0xfffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141
curve_secp256k1 = FiniteCurve(_a, _b, (_Gx, _Gy), _p, _n)
# https://en.bitcoin.it/wiki/Technical_background_of_version_1_Bitcoin_addresses
private_key = 0x3969E7AF7D041E2E8527972682E805DF63EFA7841828171C769CB3AD5FD23330
public_key = curve_secp256k1.scalar_mul(private_key)
public_key = hex(public_key[0]) # The x-coord is the compressed public key.
public_key = '02' + str(public_key)[2:]
print(public_key)
s1 = sha256(public_key.encode('utf-8')).hexdigest()
r = '00' + hashlib.new('ripemd160', s1.encode('utf-8')).hexdigest()
s2 = sha256(r.encode('utf-8')).hexdigest()
s3 = sha256(s2.encode('utf-8')).hexdigest()
checksum = s3[:8]
binary_address = r + checksum
print(binary_address)