Skip to content

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}")

Verifiable XEdDSA (VXEdDSA )