297 lines
8.4 KiB
Python
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)) |