TKK_E32232028/.venv/lib/python3.10/site-packages/lightdsa/algorithms/ecdsa.py

121 lines
3.6 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.commons import transformation
from lightdsa.interfaces.signatures import Signature
from lightdsa.commons.logger import Logger
logger = Logger(module="lightdsa/algorithms/ecdsa.py")
class ECDSA(Signature):
def __init__(
self,
keys: Optional[dict] = None,
key_size: Optional[int] = None,
hash_algorithm: Optional[str] = None,
form_name: Optional[str] = "weierstrass",
curve_name: Optional[str] = "secp256k1",
):
"""
Elliptic Curve Digital Signature Algorithm (ECDSA)
https://sefiks.com/2018/02/16/elegant-signatures-with-elliptic-curve-cryptography/
"""
self.key_size = key_size
self.form_name = form_name or "weierstrass"
self.curve_name = curve_name or "secp256k1"
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 = hash_algorithm
self.hash_algorithm = transformation.get_hash_algorithm(self.curve.n)
def generate_keys(self, key_size: int) -> dict:
"""
Generate ECDSA keys
Args:
key_size (int): size of the key
Returns:
dict: private and public
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()
logger.debug("ECDSA keys generated")
return keys
def sign(self, message: int) -> Tuple[int, int]:
"""
Sign a message with ECDSA
Args:
message (int): message to sign
Returns:
signature (Tuple[int, int]): signature
"""
# this must be a random, otherwise private can be extracted from multiple signatures
random_key = random.getrandbits(self.curve.n.bit_length())
R = random_key * self.curve.G
hashed_message = transformation.hashify(message, algorithm=self.hash_algorithm)
private_key = self.keys["private_key"]["ka"]
r = R.x
s = (
(hashed_message + r * private_key)
* pow(random_key, -1, self.curve.n)
% self.curve.n
)
return (r, s)
def verify(self, message: int, signature: Tuple[int, int]) -> bool:
"""
Verify a message with ECDSA
Args:
message (int): message to verify
signature (Tuple[int, int]): signature
Returns:
bool: True if signature is valid, False otherwise
"""
hashed_message = transformation.hashify(message, algorithm=self.hash_algorithm)
Qa = self.keys["public_key"]["Qa"]
public_key = EllipticCurvePoint(Qa[0], Qa[1], self.curve.curve)
r, s = signature
w = pow(s, -1, self.curve.n)
u1 = ((hashed_message * w) % self.curve.n) * self.curve.G
u2 = ((r * w) % self.curve.n) * public_key
checkpoint = u1 + u2
if checkpoint.x != r:
raise ValueError("Signature is invalid")
return True