Files
nutshell/cashu/core/b_dhke.py
calle e8011a0f78 Type annotations for bdhke (#140)
* annotate dhke

* raise for errors

* remove backwards compatibility

* remove old code

* remove test code
2023-03-09 17:45:50 +01:00

98 lines
2.3 KiB
Python

# Don't trust me with cryptography.
"""
Implementation of https://gist.github.com/RubenSomsen/be7a4760dd4596d06963d67baf140406
Bob (Mint):
A = a*G
return A
Alice (Client):
Y = hash_to_curve(secret_message)
r = random blinding factor
B'= Y + r*G
return B'
Bob:
C' = a*B'
(= a*Y + a*r*G)
return C'
Alice:
C = C' - r*A
(= C' - a*r*G)
(= a*Y)
return C, secret_message
Bob:
Y = hash_to_curve(secret_message)
C == a*Y
If true, C must have originated from Bob
"""
import hashlib
from secp256k1 import PrivateKey, PublicKey
def hash_to_curve(message: bytes) -> PublicKey:
"""Generates a point from the message hash and checks if the point lies on the curve.
If it does not, it tries computing a new point from the hash."""
point = None
msg_to_hash = message
while point is None:
try:
_hash = hashlib.sha256(msg_to_hash).digest()
point = PublicKey(b"\x02" + _hash, raw=True)
except:
msg_to_hash = _hash
return point
def step1_alice(
secret_msg: str, blinding_factor: bytes = None
) -> tuple[PublicKey, PrivateKey]:
Y: PublicKey = hash_to_curve(secret_msg.encode("utf-8"))
if blinding_factor:
r = PrivateKey(privkey=blinding_factor, raw=True)
else:
r = PrivateKey()
B_: PublicKey = Y + r.pubkey
return B_, r
def step2_bob(B_: PublicKey, a: PrivateKey) -> PublicKey:
C_: PublicKey = B_.mult(a)
return C_
def step3_alice(C_: PublicKey, r: PrivateKey, A: PublicKey) -> PublicKey:
C: PublicKey = C_ - A.mult(r)
return C
def verify(a: PrivateKey, C: PublicKey, secret_msg: str) -> bool:
Y: PublicKey = hash_to_curve(secret_msg.encode("utf-8"))
return C == Y.mult(a)
### Below is a test of a simple positive and negative case
# # Alice's keys
# a = PrivateKey()
# A = a.pubkey
# secret_msg = "test"
# B_, r = step1_alice(secret_msg)
# C_ = step2_bob(B_, a)
# C = step3_alice(C_, r, A)
# print("C:{}, secret_msg:{}".format(C, secret_msg))
# assert verify(a, C, secret_msg)
# assert verify(a, C + C, secret_msg) == False # adding C twice shouldn't pass
# assert verify(a, A, secret_msg) == False # A shouldn't pass
# # Test operations
# b = PrivateKey()
# B = b.pubkey
# assert -A -A + A == -A # neg
# assert B.mult(a) == A.mult(b) # a*B = A*b