mirror of https://github.com/cmehay/pytor
You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
79 lines
2.3 KiB
Python
79 lines
2.3 KiB
Python
"""
|
|
this code is a cleaned version of http://ed25519.cr.yp.to/python/ed25519.py
|
|
for python3
|
|
|
|
code released under the terms of the GNU Public License v3, copyleft 2015
|
|
yoochan
|
|
"""
|
|
import collections
|
|
|
|
Point = collections.namedtuple("Point", ["x", "y"])
|
|
|
|
|
|
class Ed25519:
|
|
"""
|
|
Generate public key from private key secret hash
|
|
"""
|
|
|
|
length = 256
|
|
|
|
def __init__(self):
|
|
self.q = 2 ** 255 - 19
|
|
self.l = 2 ** 252 + 27742317777372353535851937790883648493
|
|
self.d = -121665 * self.inverse(121666)
|
|
|
|
self.i = pow(2, (self.q - 1) // 4, self.q)
|
|
|
|
self.B = self.point(4 * self.inverse(5))
|
|
|
|
def from_bytes(self, h):
|
|
""" pick 32 bytes, return a 256 bit int """
|
|
return int.from_bytes(h[0 : self.length // 8], "little", signed=False)
|
|
|
|
def to_bytes(self, k):
|
|
return k.to_bytes(self.length // 8, "little", signed=False)
|
|
|
|
def public_key_from_hash(self, hash):
|
|
c = self.outer(self.B, int.from_bytes(hash[:32], "little"))
|
|
return self.point_to_bytes(c)
|
|
|
|
def inverse(self, x):
|
|
return pow(x, self.q - 2, self.q)
|
|
|
|
def recover(self, y):
|
|
""" given a value y, recover the preimage x """
|
|
p = (y * y - 1) * self.inverse(self.d * y * y + 1)
|
|
x = pow(p, (self.q + 3) // 8, self.q)
|
|
if (x * x - p) % self.q != 0:
|
|
x = (x * self.i) % self.q
|
|
if x % 2 != 0:
|
|
x = self.q - x
|
|
return x
|
|
|
|
def point(self, y):
|
|
""" given a value y, recover x and return the corresponding P(x, y) """
|
|
return Point(self.recover(y) % self.q, y % self.q)
|
|
|
|
def inner(self, P, Q):
|
|
""" inner product on the curve, between two points """
|
|
x = (P.x * Q.y + Q.x * P.y) * self.inverse(
|
|
1 + self.d * P.x * Q.x * P.y * Q.y
|
|
)
|
|
y = (P.y * Q.y + P.x * Q.x) * self.inverse(
|
|
1 - self.d * P.x * Q.x * P.y * Q.y
|
|
)
|
|
return Point(x % self.q, y % self.q)
|
|
|
|
def outer(self, P, n):
|
|
""" outer product on the curve, between a point and a scalar """
|
|
if n == 0:
|
|
return Point(0, 1)
|
|
Q = self.outer(P, n // 2)
|
|
Q = self.inner(Q, Q)
|
|
if n & 1:
|
|
Q = self.inner(Q, P)
|
|
return Q
|
|
|
|
def point_to_bytes(self, P):
|
|
return (P.y + ((P.x & 1) << 255)).to_bytes(self.length // 8, "little")
|