104 lines
3.8 KiB
Python
104 lines
3.8 KiB
Python
import hashlib
|
|
import random
|
|
from ecdsa import NIST256p, ellipticcurve
|
|
|
|
class DECDSA:
|
|
def __init__(self, privateKey):
|
|
self.curve = NIST256p
|
|
self.order = self.curve.order
|
|
self.generator = self.curve.generator
|
|
self.private_key = int(privateKey, 16) % self.order
|
|
self.public_key = self.private_key * self.generator
|
|
# self.generate_keypair()
|
|
|
|
# def generate_keypair(self):
|
|
# test
|
|
# self.private_key = 68643326375728294502573326707893599968874260096336631364679496614035223206444
|
|
# self.private_key = random.randint(1, self.order - 1)
|
|
# self.public_key = self.private_key * self.generator
|
|
|
|
def lift_x(self, x):
|
|
p = self.curve.curve._CurveFp__p
|
|
a = self.curve.curve._CurveFp__a
|
|
b = self.curve.curve._CurveFp__b
|
|
y_squared = (x**3 + a*x + b) % p
|
|
y = pow(y_squared, (p + 1) // 4, p)
|
|
if (y * y) % p != y_squared:
|
|
raise ValueError(f"No valid point found for x={x}")
|
|
|
|
point1 = ellipticcurve.Point(self.curve.curve, x, y)
|
|
point2 = ellipticcurve.Point(self.curve.curve, x, p - y)
|
|
if y > p - y:
|
|
return point2
|
|
else:
|
|
return point1
|
|
|
|
def sign(self, message):
|
|
m1, m2 = message[:len(message)//2], message[len(message)//2:]
|
|
h1 = hashlib.sha256(m1).digest()[1:]
|
|
h2 = hashlib.sha256(m2).digest()[1:]
|
|
z1 = int.from_bytes(h1, byteorder='big') % self.order
|
|
z2 = int.from_bytes(h2, byteorder='big') % self.order
|
|
while True:
|
|
k1 = random.randint(z1, z1*4)
|
|
k2 = random.randint(z2, z2*4)
|
|
R1 = k1 * self.generator
|
|
R2 = k2 * self.generator
|
|
r1 = R1.x() % self.order
|
|
r2 = R2.x() % self.order
|
|
R_att_x = (self.lift_x(r1) + self.lift_x(r2)).x() % self.order
|
|
|
|
# assert for checking valid points
|
|
if(R_att_x!=(R1+R2).x() % self.order):
|
|
continue
|
|
|
|
if r1 == 0 or r2 == 0:
|
|
continue
|
|
|
|
ks = pow(k1, -1, self.order) + pow(k2, -1, self.order)
|
|
s = (pow(k1*k2, -1, self.order) * (z1 + r1 * self.private_key + z2 + r2 * self.private_key) * pow(ks, -1, self.order)) % self.order
|
|
|
|
if s == 0:
|
|
continue
|
|
|
|
r1, r2, s = int(r1), int(r2), int(s)
|
|
return self.sign_to_bytes(r1, r2, s)
|
|
|
|
def verify(self, message, signature):
|
|
r1, r2, s = self.bytes_to_sign(signature)
|
|
if not (1 <= r1 < self.order and 1 <= r2 < self.order and 1 <= s < self.order):
|
|
return False
|
|
|
|
m1, m2 = message[:len(message)//2], message[len(message)//2:]
|
|
h1 = hashlib.sha256(m1).digest()[1:]
|
|
h2 = hashlib.sha256(m2).digest()[1:]
|
|
z1 = int.from_bytes(h1, byteorder='big') % self.order
|
|
z2 = int.from_bytes(h2, byteorder='big') % self.order
|
|
s_inv = pow(s, -1, self.order)
|
|
u1 = (z1 * s_inv) % self.order
|
|
u2 = (z2 * s_inv) % self.order
|
|
u3 = (r1 * s_inv) % self.order
|
|
u4 = (r2 * s_inv) % self.order
|
|
R = u1 * self.generator + u3 * self.public_key + u2 * self.generator + u4 * self.public_key
|
|
R_x = R.x() % self.order
|
|
R_att_x = (self.lift_x(r1) + self.lift_x(r2)).x() % self.order
|
|
return R_x == R_att_x
|
|
|
|
def long_to_bytes(self, x):
|
|
return x.to_bytes(32, "big")
|
|
|
|
def bytes_to_long(self, x):
|
|
return int.from_bytes(x, "big")
|
|
|
|
def sign_to_bytes(self, r1, r2, s):
|
|
first_part = self.long_to_bytes(r1)
|
|
second_part = self.long_to_bytes(r2)
|
|
third_part = self.long_to_bytes(s)
|
|
return first_part + second_part + third_part
|
|
|
|
def bytes_to_sign(self, x):
|
|
r1 = self.bytes_to_long(x[:32])
|
|
r2 = self.bytes_to_long(x[32:64])
|
|
s = self.bytes_to_long(x[64:])
|
|
return r1, r2, s
|
|
|