crypto-algorithms/elas.py

297 lines
8.4 KiB
Python

from dataclasses import dataclass
from random import randint
from random import randrange
import hashlib
import base64
@dataclass
class PrimeGaloisField:
prime: int
def __contains__(self, field_value: "FieldElement") -> bool:
return 0 <= field_value.value < self.prime
@dataclass
class FieldElement:
value: int
field: PrimeGaloisField
def __repr__(self):
return "0x" + f"{self.value:x}".zfill(64)
@property
def P(self) -> int:
return self.field.prime
def __add__(self, other: "FieldElement") -> "FieldElement":
return FieldElement(
value=(self.value + other.value) % self.P,
field=self.field
)
def __sub__(self, other: "FieldElement") -> "FieldElement":
return FieldElement(
value=(self.value - other.value) % self.P,
field=self.field
)
def __rmul__(self, scalar: int) -> "FieldValue":
return FieldElement(
value=(self.value * scalar) % self.P,
field=self.field
)
def __mul__(self, other: "FieldElement") -> "FieldElement":
return FieldElement(
value=(self.value * other.value) % self.P,
field=self.field
)
def __pow__(self, exponent: int) -> "FieldElement":
return FieldElement(
value=pow(self.value, exponent, self.P),
field=self.field
)
def __truediv__(self, other: "FieldElement") -> "FieldElement":
other_inv = other ** -1
return self * other_inv
@dataclass
class EllipticCurve:
a: int
b: int
field: PrimeGaloisField
def __contains__(self, point: "Point") -> bool:
x, y = point.x, point.y
return y ** 2 == x ** 3 + self.a * x + self.b
def __post_init__(self):
self.a = FieldElement(self.a, self.field)
self.b = FieldElement(self.b, self.field)
if self.a not in self.field or self.b not in self.field:
raise ValueError
@dataclass
class Point:
x: int
y: int
curve: EllipticCurve
def __post_init__(self):
if self.x is None and self.y is None:
return
self.x = FieldElement(self.x, self.curve.field)
self.y = FieldElement(self.y, self.curve.field)
if self not in self.curve:
raise ValueError
def __add__(self, other):
if self == I:
return other
if other == I:
return self
if self.x == other.x and self.y == (-1 * other.y):
return I
if self.x != other.x:
x1, x2 = self.x, other.x
y1, y2 = self.y, other.y
s = (y2 - y1) / (x2 - x1)
x3 = s ** 2 - x1 - x2
y3 = s * (x1 - x3) - y1
return self.__class__(
x=x3.value,
y=y3.value,
curve=self.curve
)
if self == other and self.y == inf:
return I
if self == other:
x1, y1, a = self.x, self.y, self.curve.a
s = (3 * x1 ** 2 + a) / (2 * y1)
x3 = s ** 2 - 2 * x1
y3 = s * (x1 - x3) - y1
return self.__class__(
x=x3.value,
y=y3.value,
curve=self.curve
)
def __rmul__(self, scalar: int) -> "Point":
current = self
result = I
while scalar:
if scalar & 1:
result = result + current
current = current + current
scalar >>= 1
return result
@dataclass
class Signature:
r: int
s: int
def verify(self, z: int, pub_key: Point) -> bool:
s_inv = pow(self.s, -1, N)
u = (z * s_inv) % N
v = (self.r * s_inv) % N
return (u*G + v*pub_key).x.value == self.r
@dataclass
class PrivateKey:
secret: int
def sign(self, z: int) -> Signature:
e = self.secret
k = randint(0, N)
R = k * G
r = R.x.value
k_inv = pow(k, -1, N)
s = ((z + r*e) * k_inv) % N
return Signature(r, s)
def sha256(msg: str):
hash = int('0x'+hashlib.sha256(msg.encode()).hexdigest(), 16)
return hash
def sha1(msg: str):
hash = int('0x'+hashlib.sha1(msg.encode()).hexdigest(), 16)
return hash
def lsh(msg: str):
from lsh import LSHDigest
lsh = LSHDigest.getInstance(256, 256)
lsh.update(msg.encode())
hash = lsh.final()
return hex(int.from_bytes(hash,'big'))
def largePrime(bit):
def rand(n):
return randrange(2**(n-1)+1, 2**n-1)
def gLLP(n):
while True:
# Obtain a random number
prime_candidate = rand(n)
for divisor in first_primes_list:
if prime_candidate % divisor == 0 and divisor**2 <= prime_candidate:
break
# If no divisor found, return value
else: return prime_candidate
def iMRP(miller_rabin_candidate):
maxDivisionsByTwo = 0
evenComponent = miller_rabin_candidate-1
while evenComponent % 2 == 0:
evenComponent >>= 1
maxDivisionsByTwo += 1
assert(2**maxDivisionsByTwo * evenComponent == miller_rabin_candidate-1)
def trialComposite(round_tester):
if pow(round_tester, evenComponent, miller_rabin_candidate) == 1:
return False
for i in range(maxDivisionsByTwo):
if pow(round_tester, 2**i * evenComponent, miller_rabin_candidate) == miller_rabin_candidate-1:
return False
return True
# Set number of trials here
numberOfRabinTrials = 20
for i in range(numberOfRabinTrials):
round_tester = randrange(2, miller_rabin_candidate)
if trialComposite(round_tester):
return False
return True
first_primes_list = [2, 3, 5, 7, 11, 13, 17, 19, 23, 29,
31, 37, 41, 43, 47, 53, 59, 61, 67,
71, 73, 79, 83, 89, 97, 101, 103,
107, 109, 113, 127, 131, 137, 139,
149, 151, 157, 163, 167, 173, 179,
181, 191, 193, 197, 199, 211, 223,
227, 229, 233, 239, 241, 251, 257,
263, 269, 271, 277, 281, 283, 293,
307, 311, 313, 317, 331, 337, 347, 349]
while True:
n = bit
prime_candidate = gLLP(n)
if not iMRP(prime_candidate):
continue
else:
return prime_candidate
break
def b64e(data: int):
base64_bytes = base64.b64encode(bytes.fromhex(str(data).replace('0x','')))
base64_message = base64_bytes.decode('ascii')
return base64_message
if __name__ == "__main__":
######[ SEC-P256-r1 ]#####################################################
P = 0xFFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFF
A = 0xFFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFC
B = 0x5AC635D8AA3A93E7B3EBBD55769886BC651D06B0CC53B0F63BCE3C3E27D2604B
N = 0xFFFFFFFF00000000FFFFFFFFFFFFFFFFBCE6FAADA7179E84F3B9CAC2FC632551
inf = float("inf")
field = PrimeGaloisField(prime=P)
secp256r1 = EllipticCurve(a=A, b=B, field=field)
G = Point(
x=0x6B17D1F2E12C4247F8BCE6E563A440F277037D812DEB33A0F4A13945D898C296,
y=0x4FE342E2FE1A7F9B8EE7EB4A7C0F9E162BCE33576B315ECECBB6406837BF51F5,
curve=secp256r1)
I = Point(x=None, y=None, curve=secp256r1)
#####################################################################
priv = 0x9f07090a27c7f3eaf51980059cae33420865890c72d51a8d3a20fee02c82afc63ab79c604ec6b691b94bc288b910327cd38cce7f11b61ab330b9b506c149722f
#largePrime(512)
msg = ''
z = sha256(msg)
e = PrivateKey(priv)
pub = e.secret * G
signature = e.sign(z)
# print(signature.verify(z, pub))
f_pubKey = hex(int(f'0x40{str(pub.x).replace("0x","")}{str(pub.y).replace("0x","")}',16))
f_privKey = hex(priv)
f_msg = hex(z)
f_Sign = hex(int(f'0x30450220{str(hex(e.sign(z).r)).replace("0x","")}022100{str(hex(e.sign(z).s)).replace("0x","")}',16))
print(b64e(f_pubKey))