# 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): """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): Y = hash_to_curve(secret_msg.encode("utf-8")) if blinding_factor: r = PrivateKey(privkey=blinding_factor, raw=True) else: r = PrivateKey() B_ = Y + r.pubkey return B_, r def step2_bob(B_, a): C_ = B_.mult(a) return C_ def step3_alice(C_, r, A): C = C_ - A.mult(r) return C def verify(a, C, secret_msg): Y = 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