diff --git a/cashu/core/b_dhke.py b/cashu/core/b_dhke.py index be9a141..5e9d2e5 100644 --- a/cashu/core/b_dhke.py +++ b/cashu/core/b_dhke.py @@ -6,7 +6,7 @@ Alice: A = a*G return A Bob: -Y = hash_to_point(secret_message) +Y = hash_to_curve(secret_message) r = random blinding factor B'= Y + r*G return B' @@ -20,7 +20,7 @@ C = C' - r*A (= a*Y) return C, secret_message Alice: -Y = hash_to_point(secret_message) +Y = hash_to_curve(secret_message) C == a*Y If true, C must have originated from Alice """ @@ -30,28 +30,22 @@ import hashlib from secp256k1 import PrivateKey, PublicKey -def hash_to_point(secret_msg): - """Generates x coordinate from the message hash and checks if the point lies on the curve. - If it does not, it tries computing again a new x coordinate from the hash of the coordinate.""" +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 = secret_msg + msg_to_hash = message while point is None: - _hash = hashlib.sha256(msg).hexdigest().encode("utf-8") try: - # We construct compressed pub which has x coordinate encoded with even y - _hash = list(_hash[:33]) # take the 33 bytes and get a list of bytes - _hash[0] = 0x02 # set first byte to represent even y coord - _hash = bytes(_hash) - point = PublicKey(_hash, raw=True) + _hash = hashlib.sha256(msg_to_hash).digest() + point = PublicKey(b"\x02" + _hash, raw=True) except: - msg = _hash - + msg_to_hash = _hash return point -def step1_alice(secret_msg): - secret_msg = secret_msg.encode("utf-8") - Y = hash_to_point(secret_msg) +def step1_alice(secret_msg: str): + Y = hash_to_curve(secret_msg.encode("utf-8")) r = PrivateKey() B_ = Y + r.pubkey return B_, r @@ -68,7 +62,7 @@ def step3_alice(C_, r, A): def verify(a, C, secret_msg): - Y = hash_to_point(secret_msg.encode("utf-8")) + Y = hash_to_curve(secret_msg.encode("utf-8")) return C == Y.mult(a) diff --git a/cashu/core/base.py b/cashu/core/base.py index b76b6c4..189335b 100644 --- a/cashu/core/base.py +++ b/cashu/core/base.py @@ -247,7 +247,7 @@ class MintKeyset: first_seen=None, active=None, seed: Union[None, str] = None, - derivation_path: str = "0", + derivation_path: str = None, ): self.derivation_path = derivation_path self.id = id diff --git a/cashu/core/crypto.py b/cashu/core/crypto.py index 6cad72b..8fcb496 100644 --- a/cashu/core/crypto.py +++ b/cashu/core/crypto.py @@ -6,6 +6,20 @@ from cashu.core.secp import PrivateKey, PublicKey from cashu.core.settings import MAX_ORDER +def derivation_path_newer_than(d1: str, d2: str): + """ + Returns whether derivation path d1 is newer (deeper down the derivation tree) + than d2. Used for treating tokens with old keysets differently. + """ + # NOTE: Derivation paths are still just simple integers for now. This function needs + # to change once we upgrade to BIP32. + + # the very first derivation path was "" (empty string) so anything is newer than itself + if d1 == "" and d2 != "": + return False + return int(d1) > int(d2) + + def derive_keys(master_key: str, derivation_path: str = ""): """ Deterministic derivation of keys for 2^n values. diff --git a/cashu/mint/__init__.py b/cashu/mint/__init__.py index cfe9d4c..066cf19 100644 --- a/cashu/mint/__init__.py +++ b/cashu/mint/__init__.py @@ -1,4 +1,4 @@ from cashu.core.settings import MINT_PRIVATE_KEY from cashu.mint.ledger import Ledger -ledger = Ledger(MINT_PRIVATE_KEY, "data/mint") +ledger = Ledger(MINT_PRIVATE_KEY, "data/mint", derivation_path="0") diff --git a/cashu/mint/ledger.py b/cashu/mint/ledger.py index 73126c5..1cbb93c 100644 --- a/cashu/mint/ledger.py +++ b/cashu/mint/ledger.py @@ -112,6 +112,7 @@ class Ledger: secret_key = self.keysets.keysets[proof.id].private_keys[proof.amount] C = PublicKey(bytes.fromhex(proof.C), raw=True) + return b_dhke.verify(secret_key, C, proof.secret) def _verify_script(self, idx: int, proof: Proof): diff --git a/docs/README.md b/docs/README.md index 6e3f5b3..851d5d4 100644 --- a/docs/README.md +++ b/docs/README.md @@ -17,9 +17,9 @@ Mint: `Bob` # Blind Diffie-Hellmann key exchange (BDH) - Mint `Bob` publishes `K = kG` -- `Alice` picks secret `x` and computes `Y = hash_to_point(x)` +- `Alice` picks secret `x` and computes `Y = hash_to_curve(x)` - `Alice` sends to `Bob`: `T = Y + rG` with `r` being a random nonce - `Bob` sends back to `Alice` blinded key: `Q = kT` (these two steps are the DH key exchange) - `Alice` can calculate the unblinded key as `Q - rK = kY + krG - krG = kY = Z` - Alice can take the pair `(x, Z)` as a token and can send it to `Carol`. -- `Carol` can send `(x, Z)` to `Bob` who then checks that `k*hash_to_point(x) == Z`, and if so treats it as a valid spend of a token, adding `x` to the list of spent secrets. \ No newline at end of file +- `Carol` can send `(x, Z)` to `Bob` who then checks that `k*hash_to_curve(x) == Z`, and if so treats it as a valid spend of a token, adding `x` to the list of spent secrets. \ No newline at end of file diff --git a/docs/specs/cashu_client_spec.md b/docs/specs/cashu_client_spec.md index d449804..bf537b2 100644 --- a/docs/specs/cashu_client_spec.md +++ b/docs/specs/cashu_client_spec.md @@ -17,12 +17,12 @@ Mint: `Bob` # Blind Diffie-Hellmann key exchange (BDH) - Mint `Bob` publishes `K = kG` -- `Alice` picks secret `x` and computes `Y = hash_to_point(x)` +- `Alice` picks secret `x` and computes `Y = hash_to_curve(x)` - `Alice` sends to `Bob`: `T = Y + rG` with `r` being a random nonce - `Bob` sends back to `Alice` blinded key: `Q = kT` (these two steps are the DH key exchange) - `Alice` can calculate the unblinded key as `Q - rK = kY + krG - krG = kY = Z` - Alice can take the pair `(x, Z)` as a token and can send it to `Carol`. -- `Carol` can send `(x, Z)` to `Bob` who then checks that `k*hash_to_point(x) == Z`, and if so treats it as a valid spend of a token, adding `x` to the list of spent secrets. +- `Carol` can send `(x, Z)` to `Bob` who then checks that `k*hash_to_curve(x) == Z`, and if so treats it as a valid spend of a token, adding `x` to the list of spent secrets. # Cashu client protocol