def generate_private_key(short_inverse_size=64, p=P): """ usage: generate_private_key(short_inverse_size=65, p=P) => private_key Returns 1 integer, suitable for use as a private key. """ short_inverse = (random_integer(short_inverse_size) << 1) | ( random_integer(1) & 1) return short_inverse
def test_asymmetric_encrypt_decrypt(algorithm_name, generate_keypair, encrypt, decrypt, iterations=1024, plaintext_size=32): print("Beginning {} unit test".format(algorithm_name)) print("Validating correctness...") for count in range(iterations): public_key, private_key = generate_keypair() message = random_integer(plaintext_size) ciphertext = encrypt(message, public_key) plaintext = decrypt(ciphertext, private_key) if plaintext != message: raise Warning("Unit test failed after {} successful tests".format(count)) print("...done") test_encrypt_decrypt_time(iterations, encrypt, decrypt, public_key, private_key, plaintext_size) m1, m2 = 3, 6 ciphertext1 = encrypt(m1, public_key) ciphertext2 = encrypt(m2, public_key) test_for_homomorphism(ciphertext1, ciphertext2, decrypt, private_key, m1, m2) public_sizes = determine_key_size(public_key) private_sizes = determine_key_size(private_key) print("Public key size : {}".format(sum(public_sizes))) print("Private key size: {}".format(sum(private_sizes))) print("Ciphertext size : {}".format(size_in_bits(encrypt(random_integer(32), public_key)))) print("(sizes are in bits)") print("{} unit test passed".format(algorithm_name))
def exchange_key(public_key, s_size=32, e_size=32, p=P): """ usage: exchange_key(public_key, s_size=32, e_size=32, p=P) => ciphertext, secret Returns a ciphertext and a shared secret. The ciphertext should be delivered to the holder of the associated private key, so that they may recover the shared secret. """ e = random_integer(e_size) ciphertext = 0 for element in public_key: ciphertext += element * random_integer(s_size) return (ciphertext + e) % p, e
def exchange_key(public_key, s_size=32, e_size=32, p=P): """ usage: exchange_key(public_key, s_size=32, e_size=32, p=P) => ciphertext, secret Returns a ciphertext and a shared secret. The ciphertext should be delivered to the holder of the associated private key, so that they may recover the shared secret. """ e = random_integer(e_size) ciphertext = 0 for element in public_key: ciphertext += element * random_integer(s_size) return (ciphertext + e) % p, e
def generate_backdoor_private_key(inverse_size=INVERSE_SIZE, p_size=P_SIZE): """ usage: generate_backdoor_private_key(inverse_size=INVERSE_SIZE, p_size=P_SIZE) => private_key Returns the integer(s) that constitute a private key. """ while True: inverse = random_integer(inverse_size) modulus = random_integer(p_size) try: modular_inverse(inverse, modulus) except ValueError: continue else: break return inverse, modulus
def test_encrypt_decrypt(): key = generate_secret_key() m0 = 0 m1 = 1 mr = random_integer(SECURITY_LEVEL) c0 = encrypt(m0, key) c1 = encrypt(m1, key) cr = encrypt(mr, key) p0 = decrypt(c0, key) p1 = decrypt(c1, key) pr = decrypt(cr, key) assert (m0 == p0), (m0, p0) assert (m1 == p1), (m1, p1) assert (mr == pr), (mr, pr) c1r = (c1 * mr) % Q p1r = decrypt(c1r, key) assert (mr == p1r), (mr, p1r) from epqcrypto.unittesting import test_symmetric_encrypt_decrypt test_symmetric_encrypt_decrypt("epqcrypto.secretkey (axby2)", generate_secret_key, encrypt, decrypt, iterations=10000)
def generate_backdoor_public_key(private_key, q_size=Q_SIZE): """ usage: generate_backdoor_public_key(private_key, q_size=Q_SIZE) => public_key Returns the integer(s) that constitute a public key. """ ai, modulus = private_key q = random_integer(q_size) a = modular_inverse(ai, modulus) return a, modulus + q
def generate_public_key(private_key, r_size=32, p=P, point_count=POINT_COUNT): """ usage: generate_public_key(private_key, r_size=32, p=P) => public_key Returns 1 integer, suitable for use as a public key. """ random_number = modular_inverse(private_key, p) # selects a random integer with an appropriate sized inverse by selecting the inverse first public_key = [] for count in range(point_count): point = (random_number * random_integer(r_size)) % p public_key.append(point) return public_key
def generate_secret_key(parameters=PARAMETERS): q = parameters["q"] short_inverses = [(random_integer(parameters["inverse_size"]) << parameters["inverse_shift"]) + 1 for count in range(4)] decryption_scalar = reduce(lambda a, b: (a * b) % q, short_inverses) # a * b * c * d mod q a, b, c, d = [modular_inverse(element, q) for element in short_inverses] encryption_vector = ((((b * c) % q) * d) % q, (((c * d) % q) * a) % q, (((d * a) % q) * b) % q, (((a * b) % q) * c) % q) return encryption_vector, decryption_scalar
def generate_public_key(private_key, r_size=32, p=P, point_count=POINT_COUNT): """ usage: generate_public_key(private_key, r_size=32, p=P) => public_key Returns 1 integer, suitable for use as a public key. """ random_number = modular_inverse( private_key, p ) # selects a random integer with an appropriate sized inverse by selecting the inverse first public_key = [] for count in range(point_count): point = (random_number * (random_integer(r_size) >> 1)) % p public_key.append(point) return public_key
def exchange_key(public_key, s_size=32, e_size=32, p=P): """ usage: exchange_key(public_key, s_size=32, e_size=32, p=P) => ciphertext, secret Returns a compressed ciphertext and a shared secret. The ciphertext should be delivered to the holder of the associated private key, so that they may recover the shared secret. """ c = 0 for element in public_key: c += element * random_integer(s_size) c_high = c >> 772 c = (c + c_high + (c_high << 5) + (c_high << 9)) % (2**772) e = (-c) % (2**256) c = (c >> 256) + 1 return c, e
def exchange_key(public_key, s_size=32, e_size=32, p=P): """ usage: exchange_key(public_key, s_size=32, e_size=32, p=P) => ciphertext, secret Returns a compressed ciphertext and a shared secret. The ciphertext should be delivered to the holder of the associated private key, so that they may recover the shared secret. """ c = 0 for element in public_key: c += element * random_integer(s_size) c_high = c >> 772 c = (c + c_high + (c_high << 5) + (c_high << 9)) % (2 ** 772) e = (-c) % (2 ** 256) c = (c >> 256) + 1 return c, e
def test_sign_verify_time(iterations, sign, verify, public_key, private_key, message_size=32): message = random_integer(message_size) print("Signing {} {}-bit messages...".format(iterations, message_size * 8)) before = default_timer() for count in range(iterations): signature = sign(message, private_key) after = default_timer() print("Time required: {}".format(after - before)) print("Verifying {} {}-bit signatures...".format(iterations, sum(determine_key_size(signature)))) before = default_timer() for count in range(iterations): valid_flag = verify(signature, message, public_key) after = default_timer() print("Time required: {}".format(after - before))
def test_symmetric_encrypt_decrypt(algorithm_name, generate_key, encrypt, decrypt, iterations=1024, plaintext_size=32): print("Beginning {} unit test...".format(algorithm_name)) print("Generating key...") key = generate_key() print("...done") test_encrypt_decrypt_time(iterations, encrypt, decrypt, key, key, plaintext_size) m1 = 10 m2 = 20 c1 = encrypt(m1, key) c2 = encrypt(m2, key) test_for_homomorphism(c1, c2, decrypt, key, m1, m2) key_size = determine_key_size(key) print("Key size: {}".format(sum(key_size))) print("Ciphertext size: {}".format(size_in_bits(encrypt(random_integer(plaintext_size), key)))) print("{} unit test passed".format(algorithm_name))
def test_sign_verify(algorithm_name, generate_keypair, sign, verify, iterations=1024, message_size=32): print("Beginning {} unit test...".format(algorithm_name)) print("Generating keypair...") public_key, private_key = generate_keypair() print("...done") print("Validating correctness...") for count in range(iterations): message = random_integer(message_size) signature = sign(message, private_key) if not verify(signature, message, public_key): raise BaseException("Unit test failed after {} successful signature verifications".format(count)) print("...done") test_sign_verify_time(iterations, sign, verify, public_key, private_key, message_size) public_sizes = determine_key_size(public_key) private_sizes = determine_key_size(private_key) print("Public key size : {}".format(sum(public_sizes))) print("Private key size: {}".format(sum(private_sizes))) print("Signature size : {}".format(sum(determine_key_size(signature)))) print("(sizes are in bits)") print("{} unit test passed".format(algorithm_name))
def generate_private_key(s_size=S_SIZE): return random_integer(s_size)
def generate_public_key(private_key, a=A, modulus=MODULUS, e_size=E_SIZE): s = private_key e = random_integer(e_size) from math import log print log(a, 2), log(s, 2), log(modulus, 2) return (((a * s) % modulus) >> (e_size * 8)) #<< (e_size * 8)
def encapsulate_key(public_key, parameters=PARAMETERS): key = random_integer(parameters["r_size"]) ciphertext = trapdoor.public_key_operation(key, public_key, parameters) return ciphertext, key
def generate_private_key(short_inverse_size=65, p=P): """ usage: generate_private_key(short_inverse_size=65, p=P) => private_key Returns 1 integer, suitable for use as a private key. """ short_inverse = random_integer(short_inverse_size) return short_inverse