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.
pytor/pytor/ed25519.py

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")