mirror of
https://github.com/darkrenaissance/darkfi.git
synced 2026-01-08 22:28:12 -05:00
159 lines
5.0 KiB
Python
159 lines
5.0 KiB
Python
import hashlib
|
|
import random
|
|
|
|
def ff_inv(a, p):
|
|
a %= p
|
|
|
|
# extended euclidean algorithm
|
|
# ps + at = 1
|
|
t = 0
|
|
new_t = 1
|
|
r = p
|
|
new_r = a
|
|
|
|
while new_r != 0:
|
|
quotient = r // new_r
|
|
t, new_t = new_t, t - quotient * new_t
|
|
r, new_r = new_r, r - quotient * new_r
|
|
|
|
assert r == 1
|
|
if t < 0:
|
|
t += p
|
|
|
|
return t
|
|
|
|
class EllipticCurve:
|
|
|
|
def __init__(self, p, A, B, order, G, H, J):
|
|
self.p = p
|
|
self.A = A
|
|
self.B = B
|
|
self.order = order
|
|
self.G = G
|
|
self.H = H
|
|
self.J = J
|
|
assert self.is_valid(G)
|
|
assert self.is_valid(H)
|
|
|
|
def is_valid(self, P):
|
|
x, y, z = P
|
|
if z == 0:
|
|
return x != 0 or y != 0
|
|
z_inv = ff_inv(z, self.p)
|
|
x, y = x * z_inv, y * z_inv
|
|
return y**2 % self.p == (x**3 + self.A * x + self.B) % self.p
|
|
|
|
def add(self, p1, p2):
|
|
x1, y1, z1 = p1
|
|
x2, y2, z2 = p2
|
|
|
|
if z1 == 0:
|
|
return (x2, y2, z2)
|
|
elif z2 == 0:
|
|
return (x1, y1, z1)
|
|
|
|
if x1 == x2:
|
|
if y1 != y2:
|
|
return (0, 1, 0)
|
|
|
|
assert y1 != 0
|
|
m = (3 * x1**2 + self.A) * ff_inv(2*y1, self.p)
|
|
else:
|
|
m = (y2 - y1) * ff_inv(x2 - x1, self.p)
|
|
|
|
x3 = (m**2 - x1 - x2) % self.p
|
|
y3 = (m * (x1 - x3) - y1) % self.p
|
|
return (x3, y3, 1)
|
|
|
|
def multiply(self, m, p):
|
|
bits = f"{m:b}"
|
|
result = (0, 1, 0)
|
|
temp = p
|
|
for bit in bits[::-1]:
|
|
if bit == "1":
|
|
result = self.add(result, temp)
|
|
temp = self.add(temp, temp)
|
|
return result
|
|
|
|
def random_point(self):
|
|
m = self.random_scalar()
|
|
return self.multiply(m, self.G)
|
|
|
|
def random_scalar(self):
|
|
m = random.randrange(0, self.order - 1)
|
|
return m
|
|
|
|
def random_base(self):
|
|
m = random.randrange(0, self.p - 1)
|
|
return m
|
|
|
|
def pallas_curve():
|
|
# Pallas
|
|
p = 0x40000000000000000000000000000000224698fc094cf91b992d30ed00000001
|
|
q = 0x40000000000000000000000000000000224698fc0994a8dd8c46eb2100000001
|
|
G = (5, 5392431450607408583390510508521091931943415030464003135511088002453056875732, 1)
|
|
H = (9762257241998025279988087154025308614062019274413483967640476725944341089207,
|
|
12058632856930756995627167820351407063813260358041446014729496773111030695755, 1)
|
|
J = (7795559447963065356059848000022900528974048197507738248625163674930282081839,
|
|
5156492880772775379342191094371887365795329446468828588866320184016504353483, 1)
|
|
ec = EllipticCurve(p, 0, 5, q, G, H, J)
|
|
A = (144931808354919915876542440378319484704499556634959420306426167479163065488,
|
|
2699682121356767698440748624399854659825391162912545787181017961871465868196, 1)
|
|
B = (16017037670495191561606513965775243786961447026019262496667491008912834496943,
|
|
20395164507282344548629891414360366999207473153143014512687861307997120664849, 1)
|
|
assert ec.add(A, B) == (2414658659502531855741199170408914396997834981355655923471364687102714431309, 21133344194418979683767005688724798091220515434220043854575260979109407444719, 1)
|
|
m = 26322809409216846271933211244226061368157231119725763192402071651286829040466
|
|
assert ec.multiply(m, G) == (15862887453366837597569434439063150886012590021428640083047997467990450633825, 25887284719793568129480941070850220101898092026705204234126448799557008384178, 1)
|
|
return ec
|
|
|
|
def pedersen_encrypt(x, y, ec):
|
|
vcv = ec.multiply(x, ec.G)
|
|
vcr = ec.multiply(y, ec.H)
|
|
return ec.add(vcv, vcr)
|
|
|
|
def _add_to_hasher(hasher, args):
|
|
for arg in args:
|
|
match arg:
|
|
case int() as arg:
|
|
hasher.update(arg.to_bytes(32, byteorder="little"))
|
|
case bytes() as arg:
|
|
hasher.update(arg)
|
|
case list() as arg:
|
|
_add_to_hasher(hasher, arg)
|
|
case _:
|
|
raise Exception(f"unknown hash arg '{arg}' type: {type(arg)}")
|
|
|
|
def ff_hash(p, *args):
|
|
hasher = hashlib.sha256()
|
|
_add_to_hasher(hasher, args)
|
|
value = int.from_bytes(hasher.digest(), byteorder="little")
|
|
return value % p
|
|
|
|
def hash_point(point, message=None):
|
|
hasher = hashlib.sha256()
|
|
for x_i in point:
|
|
hasher.update(x_i.to_bytes(32, byteorder="little"))
|
|
# Optional message
|
|
if message is not None:
|
|
hasher.update(message)
|
|
value = int.from_bytes(hasher.digest(), byteorder="little")
|
|
return value
|
|
|
|
def sign(message, secret, ec):
|
|
ephem_secret = ec.random_scalar()
|
|
ephem_public = ec.multiply(ephem_secret, ec.G)
|
|
challenge = hash_point(ephem_public, message) % ec.order
|
|
response = (ephem_secret + challenge * secret) % ec.order
|
|
return ephem_public, response
|
|
|
|
def verify(message, signature, public, ec):
|
|
ephem_public, response = signature
|
|
challenge = hash_point(ephem_public, message) % ec.order
|
|
# sG
|
|
lhs = ec.multiply(response, ec.G)
|
|
# R + cP
|
|
rhs_cP = ec.multiply(challenge, public)
|
|
rhs = ec.add(ephem_public, rhs_cP)
|
|
return lhs == rhs
|
|
|