Skip to content

Commit

Permalink
add domain separation wallet
Browse files Browse the repository at this point in the history
  • Loading branch information
callebtc committed Feb 10, 2024
1 parent dd38a18 commit 940fd39
Show file tree
Hide file tree
Showing 3 changed files with 59 additions and 5 deletions.
46 changes: 44 additions & 2 deletions cashu/core/crypto/b_dhke.py
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,26 @@ def hash_to_curve(message: bytes) -> PublicKey:
return point


DOMAIN_SEPARATOR = b"Secp256k1_HashToCurve_"


def hash_to_curve_domain_separated(message: bytes) -> PublicKey:
"""Generates a point from the message hash and checks if the point lies on the curve.
If it does not, iteratively tries to compute a new point from the hash."""
point = None
msg_to_hash = DOMAIN_SEPARATOR + message
counter = 0
while point is None:
_hash = hashlib.sha256(msg_to_hash + str(counter).encode()).digest()
try:
# will error if point does not lie on curve
point = PublicKey(b"\x02" + _hash, raw=True)
except Exception:
msg_to_hash = _hash
counter += 1
return point


def step1_alice(
secret_msg: str, blinding_factor: Optional[PrivateKey] = None
) -> tuple[PublicKey, PrivateKey]:
Expand All @@ -80,6 +100,15 @@ def step1_alice(
return B_, r


def step1_alice_domain_separated(
secret_msg: str, blinding_factor: Optional[PrivateKey] = None
) -> tuple[PublicKey, PrivateKey]:
Y: PublicKey = hash_to_curve_domain_separated(secret_msg.encode("utf-8"))
r = blinding_factor or PrivateKey()
B_: PublicKey = Y + r.pubkey # type: ignore
return B_, r


def step2_bob(B_: PublicKey, a: PrivateKey) -> Tuple[PublicKey, PrivateKey, PrivateKey]:
C_: PublicKey = B_.mult(a) # type: ignore
# produce dleq proof
Expand All @@ -94,7 +123,13 @@ def step3_alice(C_: PublicKey, r: PrivateKey, A: PublicKey) -> PublicKey:

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) # type: ignore
valid = C == Y.mult(a) # type: ignore
# BEGIN: BACKWARDS COMPATIBILITY < 0.15.1
if not valid:
Y1: PublicKey = hash_to_curve_domain_separated(secret_msg.encode("utf-8"))
return C == Y1.mult(a) # type: ignore
# END: BACKWARDS COMPATIBILITY < 0.15.1
return valid


def hash_e(*publickeys: PublicKey) -> bytes:
Expand Down Expand Up @@ -149,7 +184,14 @@ def carol_verify_dleq(
Y: PublicKey = hash_to_curve(secret_msg.encode("utf-8"))
C_: PublicKey = C + A.mult(r) # type: ignore
B_: PublicKey = Y + r.pubkey # type: ignore
return alice_verify_dleq(B_, C_, e, s, A)
valid = alice_verify_dleq(B_, C_, e, s, A)
# BEGIN: BACKWARDS COMPATIBILITY < 0.15.1
if not valid:
Y1: PublicKey = hash_to_curve_domain_separated(secret_msg.encode("utf-8"))
B_1: PublicKey = Y1 + r.pubkey # type: ignore
return alice_verify_dleq(B_1, C_, e, s, A)
# END: BACKWARDS COMPATIBILITY < 0.15.1
return valid


# Below is a test of a simple positive and negative case
Expand Down
2 changes: 1 addition & 1 deletion cashu/core/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,7 @@ class WalletSettings(CashuSettings):
mint_port: int = Field(default=3338)
wallet_name: str = Field(default="wallet")
wallet_unit: str = Field(default="sat")

wallet_domain_separation: bool = Field(default=False)
api_port: int = Field(default=4448)
api_host: str = Field(default="127.0.0.1")

Expand Down
16 changes: 14 additions & 2 deletions cashu/wallet/wallet.py
Original file line number Diff line number Diff line change
Expand Up @@ -1120,7 +1120,14 @@ async def _construct_proofs(
C = b_dhke.step3_alice(
C_, r, self.keysets[promise.id].public_keys[promise.amount]
)
B_, r = b_dhke.step1_alice(secret, r) # recompute B_ for dleq proofs
# BEGIN: BACKWARDS COMPATIBILITY < 0.15.1
if not settings.wallet_domain_separation:
B_, r = b_dhke.step1_alice(secret, r) # recompute B_ for dleq proofs
# END: BACKWARDS COMPATIBILITY < 0.15.1
else:
B_, r = b_dhke.step1_alice_domain_separated(
secret, r
) # recompute B_ for dleq proofs

proof = Proof(
id=promise.id,
Expand Down Expand Up @@ -1183,7 +1190,12 @@ def _construct_outputs(
rs_ = [None] * len(amounts) if not rs else rs
rs_return: List[PrivateKey] = []
for secret, amount, r in zip(secrets, amounts, rs_):
B_, r = b_dhke.step1_alice(secret, r or None)
# BEGIN: BACKWARDS COMPATIBILITY < 0.15.1
if not settings.wallet_domain_separation:
B_, r = b_dhke.step1_alice(secret, r or None)
# END: BACKWARDS COMPATIBILITY < 0.15.1
else:
B_, r = b_dhke.step1_alice_domain_separated(secret, r or None)
rs_return.append(r)
output = BlindedMessage(
amount=amount, B_=B_.serialize().hex(), id=self.keyset_id
Expand Down

0 comments on commit 940fd39

Please sign in to comment.