diff --git a/cashu/core/crypto/b_dhke.py b/cashu/core/crypto/b_dhke.py index 4abf1b77..ad7ba1aa 100644 --- a/cashu/core/crypto/b_dhke.py +++ b/cashu/core/crypto/b_dhke.py @@ -136,12 +136,17 @@ def verify(a: PrivateKey, C: PublicKey, secret_msg: str) -> bool: 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 + return verify_domain_separated(a, C, secret_msg) # END: BACKWARDS COMPATIBILITY < 0.15.1 return valid +def verify_domain_separated(a: PrivateKey, C: PublicKey, secret_msg: str) -> bool: + Y: PublicKey = hash_to_curve_domain_separated(secret_msg.encode("utf-8")) + valid = C == Y.mult(a) # type: ignore + return valid + + def hash_e(*publickeys: PublicKey) -> bytes: e_ = "" for p in publickeys: @@ -197,13 +202,26 @@ def carol_verify_dleq( 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) + return carol_verify_dleq_domain_separated(secret_msg, r, C, e, s, A) # END: BACKWARDS COMPATIBILITY < 0.15.1 return valid +def carol_verify_dleq_domain_separated( + secret_msg: str, + r: PrivateKey, + C: PublicKey, + e: PrivateKey, + s: PrivateKey, + A: PublicKey, +) -> bool: + Y: PublicKey = hash_to_curve_domain_separated(secret_msg.encode("utf-8")) + C_: PublicKey = C + A.mult(r) # type: ignore + B_: PublicKey = Y + r.pubkey # type: ignore + valid = alice_verify_dleq(B_, C_, e, s, A) + return valid + + # Below is a test of a simple positive and negative case # # Alice's keys diff --git a/tests/test_crypto.py b/tests/test_crypto.py index 59b94849..a74e8b56 100644 --- a/tests/test_crypto.py +++ b/tests/test_crypto.py @@ -1,9 +1,12 @@ from cashu.core.crypto.b_dhke import ( alice_verify_dleq, carol_verify_dleq, + carol_verify_dleq_domain_separated, hash_e, hash_to_curve, + hash_to_curve_domain_separated, step1_alice, + step1_alice_domain_separated, step2_bob, step2_bob_dleq, step3_alice, @@ -277,7 +280,7 @@ def test_dleq_alice_direct_verify_dleq(): assert alice_verify_dleq(B_, C_, e, s, A) -def test_dleq_carol_varify_from_bob(): +def test_dleq_carol_verify_from_bob(): a = PrivateKey( privkey=bytes.fromhex( "0000000000000000000000000000000000000000000000000000000000000001" @@ -300,3 +303,77 @@ def test_dleq_carol_varify_from_bob(): # carol does not know B_ and C_, but she receives C and r from Alice assert carol_verify_dleq(secret_msg=secret_msg, C=C, r=r, e=e, s=s, A=A) + + +# TESTS FOR DOMAIN SEPARATED HASH TO CURVE + + +def test_hash_to_curve_domain_separated(): + result = hash_to_curve_domain_separated( + bytes.fromhex( + "0000000000000000000000000000000000000000000000000000000000000000" + ) + ) + assert ( + result.serialize().hex() + == "024cce997d3b518f739663b757deaec95bcd9473c30a14ac2fd04023a739d1a725" + ) + + +def test_hash_to_curve_domain_separated_iterative(): + result = hash_to_curve_domain_separated( + bytes.fromhex( + "0000000000000000000000000000000000000000000000000000000000000001" + ) + ) + assert ( + result.serialize().hex() + == "022e7158e11c9506f1aa4248bf531298daa7febd6194f003edcd9b93ade6253acf" + ) + + +def test_step1_domain_separated(): + secret_msg = "test_message" + B_, blinding_factor = step1_alice_domain_separated( + secret_msg, + blinding_factor=PrivateKey( + privkey=bytes.fromhex( + "0000000000000000000000000000000000000000000000000000000000000001" + ) # 32 bytes + ), + ) + + assert ( + B_.serialize().hex() + == "025cc16fe33b953e2ace39653efb3e7a7049711ae1d8a2f7a9108753f1cdea742b" + ) + assert blinding_factor.private_key == bytes.fromhex( + "0000000000000000000000000000000000000000000000000000000000000001" + ) + + +def test_dleq_carol_verify_from_bob_domain_separated(): + a = PrivateKey( + privkey=bytes.fromhex( + "0000000000000000000000000000000000000000000000000000000000000001" + ), + raw=True, + ) + A = a.pubkey + assert A + secret_msg = "test_message" + r = PrivateKey( + privkey=bytes.fromhex( + "0000000000000000000000000000000000000000000000000000000000000001" + ), + raw=True, + ) + B_, _ = step1_alice_domain_separated(secret_msg, r) + C_, e, s = step2_bob(B_, a) + assert alice_verify_dleq(B_, C_, e, s, A) + C = step3_alice(C_, r, A) + + # carol does not know B_ and C_, but she receives C and r from Alice + assert carol_verify_dleq_domain_separated( + secret_msg=secret_msg, C=C, r=r, e=e, s=s, A=A + )