Skip to content

Commit

Permalink
fix tests
Browse files Browse the repository at this point in the history
  • Loading branch information
callebtc committed Oct 4, 2023
1 parent a3cdee7 commit ce6a673
Show file tree
Hide file tree
Showing 7 changed files with 59 additions and 26 deletions.
30 changes: 23 additions & 7 deletions cashu/core/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,12 @@
from loguru import logger
from pydantic import BaseModel

from .crypto.keys import derive_keys, derive_keyset_id, derive_pubkeys
from .crypto.keys import (
derive_keys,
derive_keyset_id,
derive_keyset_id_deprecated,
derive_pubkeys,
)
from .crypto.secp import PrivateKey, PublicKey
from .legacy import derive_keys_backwards_compatible_insecure_pre_0_12
from .p2pk import P2SHScript
Expand Down Expand Up @@ -320,6 +325,7 @@ def __init__(
self.public_keys = public_keys
# overwrite id by deriving it from the public keys
self.id = derive_keyset_id(self.public_keys)
self.id_deprecated = derive_keyset_id_deprecated(self.public_keys)

def serialize(self):
return json.dumps(
Expand Down Expand Up @@ -400,27 +406,37 @@ def public_keys_hex(self) -> Dict[int, str]:

def generate_keys(self, seed):
"""Generates keys of a keyset from a seed."""
backwards_compatibility_pre_0_12 = False
if (
self.version
and len(self.version.split(".")) > 1
and int(self.version.split(".")[0]) == 0
and int(self.version.split(".")[1]) <= 11
):
backwards_compatibility_pre_0_12 = True
# WARNING: Broken key derivation for backwards compatibility with < 0.12
self.private_keys = derive_keys_backwards_compatible_insecure_pre_0_12(
seed, self.derivation_path
)
logger.warning(
f"WARNING: Using weak key derivation for keyset {self.id} (backwards"
" compatibility < 0.12)"
)
else:
self.private_keys = derive_keys(seed, self.derivation_path)
self.public_keys = derive_pubkeys(self.private_keys) # type: ignore
self.id = derive_keyset_id(self.public_keys) # type: ignore
if backwards_compatibility_pre_0_12:

if (
self.version
and len(self.version.split(".")) > 1
and int(self.version.split(".")[0]) == 0
and int(self.version.split(".")[1]) <= 13
):
self.id = derive_keyset_id_deprecated(self.public_keys) # type: ignore
logger.warning(
f"WARNING: Using weak key derivation for keyset {self.id} (backwards"
" compatibility < 0.12)"
"WARNING: Using deriving keyset id with old base64 format"
f" {self.id} (backwards compatibility < 0.14)"
)
else:
self.id = derive_keyset_id(self.public_keys) # type: ignore


class MintKeysets:
Expand Down
10 changes: 10 additions & 0 deletions cashu/core/crypto/keys.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,16 @@ def derive_keyset_id(keys: Dict[int, PublicKey]):
# sort public keys by amount
sorted_keys = dict(sorted(keys.items()))
pubkeys_concat = "".join([p.serialize().hex() for _, p in sorted_keys.items()])
return hashlib.sha256(pubkeys_concat.encode("utf-8")).hexdigest()[:16]


def derive_keyset_id_deprecated(keys: Dict[int, PublicKey]):
"""DEPRECATED: Deterministic derivation keyset_id from set of public keys.
DEPRECATION: This method produces base64 keyset ids. Use `derive_keyset_id` instead.
"""
# sort public keys by amount
sorted_keys = dict(sorted(keys.items()))
pubkeys_concat = "".join([p.serialize().hex() for _, p in sorted_keys.items()])
return base64.b64encode(
hashlib.sha256((pubkeys_concat).encode("utf-8")).digest()
).decode()[:12]
Expand Down
14 changes: 11 additions & 3 deletions cashu/wallet/secrets.py
Original file line number Diff line number Diff line change
Expand Up @@ -117,9 +117,17 @@ async def generate_determinstic_secret(
"""
assert self.bip32, "BIP32 not initialized yet."
# integer keyset id modulo max number of bip32 child keys
keyest_id = int.from_bytes(base64.b64decode(self.keyset_id), "big") % (
2**31 - 1
)
try:
keyest_id = int.from_bytes(bytes.fromhex(self.keyset_id), "big") % (
2**31 - 1
)
except ValueError:
# BEGIN: backwards compatibility keyset id is not hex
keyest_id = int.from_bytes(base64.b64decode(self.keyset_id), "big") % (
2**31 - 1
)
# END: backwards compatibility keyset id is not hex

logger.trace(f"keyset id: {self.keyset_id} becomes {keyest_id}")
token_derivation_path = f"m/129372'/0'/{keyest_id}'/{counter}'"
# for secret
Expand Down
2 changes: 1 addition & 1 deletion tests/test_mint.py
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ async def test_privatekeys(ledger: Ledger):
async def test_keysets(ledger: Ledger):
assert len(ledger.keysets.keysets)
assert len(ledger.keysets.get_ids())
assert ledger.keyset.id == "1cCNIAZ2X/w1"
assert ledger.keyset.id == "d5c08d2006765ffc"


@pytest.mark.asyncio
Expand Down
4 changes: 1 addition & 3 deletions tests/test_mint_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,9 +31,7 @@ async def test_api_keysets(ledger):

@pytest.mark.asyncio
async def test_api_keyset_keys(ledger):
response = requests.get(
f"{BASE_URL}/keys/{'1cCNIAZ2X/w1'.replace('/', '_').replace('+', '-')}"
)
response = requests.get(f"{BASE_URL}/keys/d5c08d2006765ffc")
assert response.status_code == 200, f"{response.url} {response.status_code}"
assert response.json()["keysets"][0]["keys"] == {
str(k): v.serialize().hex() for k, v in ledger.keyset.public_keys.items()
Expand Down
3 changes: 2 additions & 1 deletion tests/test_wallet.py
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,8 @@ async def test_get_keys(wallet1: Wallet):
assert len(wallet1.keys.public_keys) == settings.max_order
keyset = await wallet1._get_keys(wallet1.url)
assert keyset.id is not None
assert keyset.id == "1cCNIAZ2X/w1"
assert keyset.id_deprecated == "1cCNIAZ2X/w1"
assert keyset.id == "d5c08d2006765ffc"
assert isinstance(keyset.id, str)
assert len(keyset.id) > 0

Expand Down
22 changes: 11 additions & 11 deletions tests/test_wallet_restore.py
Original file line number Diff line number Diff line change
Expand Up @@ -94,23 +94,23 @@ async def test_bump_secret_derivation(wallet3: Wallet):
)
secrets1, rs1, derivation_paths1 = await wallet3.generate_n_secrets(5)
secrets2, rs2, derivation_paths2 = await wallet3.generate_secrets_from_to(0, 4)
assert wallet3.keyset_id == "1cCNIAZ2X/w1"
assert wallet3.keyset_id == "d5c08d2006765ffc"
assert secrets1 == secrets2
assert [r.private_key for r in rs1] == [r.private_key for r in rs2]
assert derivation_paths1 == derivation_paths2
assert secrets1 == [
"9d32fc57e6fa2942d05ee475d28ba6a56839b8cb8a3f174b05ed0ed9d3a420f6",
"1c0f2c32e7438e7cc992612049e9dfcdbffd454ea460901f24cc429921437802",
"327c606b761af03cbe26fa13c4b34a6183b868c52cda059fe57fdddcb4e1e1e7",
"53476919560398b56c0fdc5dd92cf8628b1e06de6f2652b0f7d6e8ac319de3b7",
"b2f5d632229378a716be6752fc79ac8c2b43323b820859a7956f2dfe5432b7b4",
"064d8f585385fdc01c5e1363cf4d80cae8af6aa36263459cd902667041afacae",
"e273fe79f152071a9d430d0de56248f1e8f88b06c6e231d48b8d7f073d5dc852",
"7f59ebf0c1d841819b9e2d0c221a5309022aadd34f65426158bf3906faca31ec",
"9b0d6cc849823923bbcfa2101874755c108b4cf7a3b721f851d0ee7662581f2d",
"1f23400a377aa089d04fa17163a93aab77e397f22a3381fc5ee0ab3328594f5c",
]
assert derivation_paths1 == [
"m/129372'/0'/2004500376'/0'",
"m/129372'/0'/2004500376'/1'",
"m/129372'/0'/2004500376'/2'",
"m/129372'/0'/2004500376'/3'",
"m/129372'/0'/2004500376'/4'",
"m/129372'/0'/838302271'/0'",
"m/129372'/0'/838302271'/1'",
"m/129372'/0'/838302271'/2'",
"m/129372'/0'/838302271'/3'",
"m/129372'/0'/838302271'/4'",
]


Expand Down

0 comments on commit ce6a673

Please sign in to comment.