XEdDSA
XEdDSA¶
https://signal.org/docs/specifications/xeddsa/
Implimentation¶
from ecc_lib import *
import hashlib, os, math
from cryptopals_lib import bytes_to_int, int_to_bytes, secure_rand_between
def xeddsa_sign(private_key, message, nonce=secure_rand_between(1, 2**64), curve_generator=Curve25519_Generator_Point, hash_obj=hashlib.sha512):
#Derive Information
curve = curve_generator.curve
order = curve.order
public_key = curve_generator * private_key
#r = hash1(private_key || message || nonce) (mod q)
hash_bytes = hash_obj( int_to_bytes(private_key) + message + nonce ).digest()
random_r = bytes_to_int(hash_bytes) % order
#R = rB
random_point = curve_generator * random_r
#h = hash(R || public_key || message) (mod q)
hash_bytes = hash_obj(random_point.compressed() + public_key.compressed() + message ).digest()
hash_int = bytes_to_int(hash_bytes) % order
#s = r + ha (mod q)
signature = (random_r + (hash_int * private_key )) % order
#return R || s
return {"random_point": random_point, "signature": signature}
def xeddsa_verify(public_key, message, signature, curve_generator=Curve25519_Generator_Point, hash_obj=hashlib.sha512):
#Derive Information
curve = curve_generator.curve
order = curve.order
prime_mod = curve.prime_mod
#Check Inputs for bounds
#if public_key >= p:
if public_key.x >= prime_mod or public_key.y >= prime_mod:
raise Exception("Invalid public_key")
#if random_point.y >= 2^|p| or s >= 2^|q|
if signature["random_point"].y >= 2**(math.ceil(math.log2(prime_mod))) or signature["signature"] >= 2**(math.ceil(math.log2(order))):
raise Exception("Invalid signature")
#Check if Public Key is on the Curve
if not curve.is_on_curve(public_key):
raise Exception(f"public_key is not on {curve.name}")
#h = hash(random_point || public_key || message) (mod q)
hash_bytes = hash_obj(signature["random_point"].compressed() + public_key.compressed() + message ).digest()
hash_int = bytes_to_int(hash_bytes) % order
#Rcheck = s*generator - h*public_key
check_random_point = (curve_generator * signature["signature"]) - (hash_int * public_key)
return check_random_point == signature["random_point"]
if __name__ == '__main__':
#Generate Keys
message = b"Test Message"
nonce = os.urandom(64)
#Generate KeyPair
private_key, public_point = generate_KeyPair(Curve25519_Generator_Point)
print(private_key, public_point)
#Sign message
signature = xeddsa_sign(private_key, message, nonce)
print(signature)
#Verify Message
verify = xeddsa_verify(public_point, message, signature)
print(f"The Signature has been verified as {verify}")