111 lines
3.4 KiB
Python
111 lines
3.4 KiB
Python
# built-in dependencies
|
|
import random
|
|
from typing import Optional, Tuple
|
|
|
|
# 3rd party dependencies
|
|
from lightecc import LightECC
|
|
from lightecc.interfaces.elliptic_curve import EllipticCurvePoint
|
|
|
|
# project dependencies
|
|
from lightdsa.interfaces.signatures import Signature
|
|
from lightdsa.commons import transformation
|
|
from lightdsa.commons.logger import Logger
|
|
|
|
logger = Logger(module="lightdsa/algorithms/eddsa.py")
|
|
|
|
|
|
class EdDSA(Signature):
|
|
def __init__(
|
|
self,
|
|
keys: Optional[dict] = None,
|
|
key_size: Optional[int] = None,
|
|
form_name: Optional[str] = "edwards",
|
|
curve_name: Optional[str] = "ed25519",
|
|
):
|
|
"""
|
|
Edwards Curve Digital Signature Algorithm (EdDSA)
|
|
https://sefiks.com/2018/12/24/a-gentle-introduction-to-edwards-curve-digital-signature-algorithm-eddsa/
|
|
"""
|
|
self.key_size = key_size
|
|
self.form_name = form_name or "edwards"
|
|
self.curve_name = curve_name or "ed25519"
|
|
self.curve = LightECC(self.form_name, self.curve_name)
|
|
self.keys = keys or self.generate_keys(key_size or self.curve.n.bit_length())
|
|
self.hash_algorithm = transformation.get_hash_algorithm(self.curve.n)
|
|
|
|
def generate_keys(self, key_size: int) -> dict:
|
|
"""
|
|
Generate public and private keys for EdDSA
|
|
Args:
|
|
key_size: int
|
|
Returns:
|
|
keys (dict): public and private keys
|
|
e.g. keys = {
|
|
"private_key": {
|
|
"ka": int
|
|
},
|
|
"public_key": {
|
|
"Qa": Tuple[int, int]
|
|
}
|
|
}
|
|
"""
|
|
keys = {}
|
|
keys["private_key"] = {}
|
|
keys["public_key"] = {}
|
|
|
|
# private key
|
|
ka = random.getrandbits(key_size)
|
|
keys["private_key"]["ka"] = ka
|
|
|
|
# public key
|
|
Qa = ka * self.curve.G
|
|
keys["public_key"]["Qa"] = Qa.get_point()
|
|
|
|
return keys
|
|
|
|
def sign(self, message: int) -> Tuple[Tuple[int, int], int]:
|
|
"""
|
|
Sign a message using EdDSA
|
|
Args:
|
|
message: int
|
|
Returns:
|
|
signature (Tuple[Tuple[int, int], int]): signature of the message
|
|
"""
|
|
r = (
|
|
transformation.hashify(
|
|
transformation.hashify(message, algorithm=self.hash_algorithm) + message
|
|
)
|
|
) % self.curve.modulo
|
|
|
|
R = r * self.curve.G
|
|
h = (R.x + self.keys["public_key"]["Qa"][0] + message) % self.curve.modulo
|
|
s = r + (h * self.keys["private_key"]["ka"])
|
|
return (R.get_point(), s)
|
|
|
|
def verify(self, message: int, signature: Tuple[Tuple[int, int], int]) -> bool:
|
|
"""
|
|
Verify a message using EdDSA
|
|
Args:
|
|
message: int
|
|
signature (Tuple[Tuple[int, int], int]): signature of the message
|
|
Returns:
|
|
bool: True if the signature
|
|
"""
|
|
(Rx, Ry), s = signature
|
|
|
|
R = EllipticCurvePoint(x=Rx, y=Ry, curve=self.curve.curve)
|
|
public_key = EllipticCurvePoint(
|
|
x=self.keys["public_key"]["Qa"][0],
|
|
y=self.keys["public_key"]["Qa"][1],
|
|
curve=self.curve.curve,
|
|
)
|
|
|
|
h = (R.x + self.keys["public_key"]["Qa"][0] + message) % self.curve.modulo
|
|
P1 = s * self.curve.G
|
|
P2 = R + h * public_key
|
|
|
|
if P1 != P2:
|
|
raise ValueError("Signature is invalid")
|
|
|
|
return True
|