Skip to content

Commit

Permalink
ephemeral key for quote
Browse files Browse the repository at this point in the history
  • Loading branch information
lollerfirst committed Nov 13, 2024
1 parent 01590b9 commit 3b1109b
Show file tree
Hide file tree
Showing 4 changed files with 27 additions and 8 deletions.
1 change: 1 addition & 0 deletions cashu/mint/features.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
SCRIPT_NUT,
STATE_NUT,
WEBSOCKETS_NUT,
QUOTE_SIGNATURE_NUT,
)
from ..core.settings import settings
from ..mint.protocols import SupportsBackends
Expand Down
2 changes: 1 addition & 1 deletion cashu/mint/ledger.py
Original file line number Diff line number Diff line change
Expand Up @@ -553,7 +553,7 @@ async def mint(
raise TransactionError("Mint quote already issued.")
if not quote.paid:
raise QuoteNotPaidError()
if quote.pubkey and quote.pubkey != "":
if quote.key and quote.key != "":
if witness is None:
raise QuoteWitnessNotProvidedError()
self._verify_quote_signature(quote, outputs, witness)
Expand Down
4 changes: 3 additions & 1 deletion cashu/mint/verification.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
MintKeyset,
Proof,
Unit,
MintQuote,
)
from ..core.crypto import b_dhke
from ..core.crypto.secp import PublicKey
Expand All @@ -19,6 +20,7 @@
SecretTooLongError,
TransactionError,
TransactionUnitError,
QuoteInvalidWitnessError,
)
from ..core.settings import settings
from ..lightning.base import LightningBackend
Expand Down Expand Up @@ -282,7 +284,7 @@ def _verify_quote_signature(
self, quote: MintQuote, outputs: List[BlindedMessage], signature: str,
) -> None:
"""Verify signature on quote id and outputs"""
pubkey = PublicKey(bytes.fromhex(quote.key), raw=True)
pubkey = PublicKey(bytes.fromhex(quote.key), raw=True) # type: ignore
sigbytes = bytes.fromhex(signature)
serialized_outputs = b"".join([o.json().encode("utf-8") for o in outputs])
msgbytes = quote.quote.encode("utf-8") + serialized_outputs
Expand Down
28 changes: 22 additions & 6 deletions cashu/wallet/wallet.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
sum_promises,
sum_proofs,
)
from ..core.nuts import QUOTE_SIGNATURE_NUT
from ..core.json_rpc.base import JSONRPCSubscriptionKinds
from ..core.migrations import migrate_databases
from ..core.models import (
Expand Down Expand Up @@ -386,19 +387,19 @@ async def _check_used_secrets(self, secrets):
logger.trace("Secret check complete.")

async def request_mint_with_callback(
self, amount: int, callback: Callable, memo: Optional[str] = None, privkey: Optional[PrivateKey] = None,
self, amount: int, callback: Callable, memo: Optional[str] = None
) -> Tuple[MintQuote, SubscriptionManager]:
"""Request a quote invoice for minting tokens.
Args:
amount (int): Amount for Lightning invoice in satoshis
callback (Callable): Callback function to be called when the invoice is paid.
memo (Optional[str], optional): Memo for the Lightning invoice. Defaults
privkey (Optional[PrivateKey], optional): [NUT-19] Private key to lock the quote to. Defaults to None.
Returns:
MintQuote: Mint Quote
"""
privkey = await self.get_quote_ephemeral_key()
pubkey = (privkey.pubkey.serialize(True).hex() if privkey else None)
mint_qoute = await super().mint_quote(amount, self.unit, memo, pubkey)
subscriptions = SubscriptionManager(self.url)
Expand All @@ -410,35 +411,50 @@ async def request_mint_with_callback(
filters=[mint_qoute.quote],
callback=callback,
)
quote = MintQuote.from_resp_wallet(mint_qoute, self.url, amount, self.unit.name, privkey.serialize())
quote = MintQuote.from_resp_wallet(mint_qoute, self.url, amount, self.unit.name,
privkey.serialize() if privkey else None
)
await store_bolt11_mint_quote(db=self.db, quote=quote)

return quote, subscriptions

async def request_mint(self,
amount: int,
memo: Optional[str] = None,
privkey: Optional[PrivateKey] = None,
) -> MintQuote:
"""Request a quote invoice for minting tokens.
Args:
amount (int): Amount for Lightning invoice in satoshis
callback (Optional[Callable], optional): Callback function to be called when the invoice is paid. Defaults to None.
memo (Optional[str], optional): Memo for the Lightning invoice. Defaults to None.
privkey (Optional[PrivateKey], optional): [NUT-19] Private key to lock the quote to. Defaults to None.
Returns:
MintQuote: Mint Quote
"""
privkey = await self.get_quote_ephemeral_key()
pubkey = (privkey.pubkey.serialize(True).hex() if privkey else None)
mint_quote_response = await super().mint_quote(amount, self.unit, memo, pubkey)
quote = MintQuote.from_resp_wallet(
mint_quote_response, self.url, amount, self.unit.name, privkey.serialize()
mint_quote_response, self.url, amount, self.unit.name,
privkey.serialize() if privkey else None,
)
await store_bolt11_mint_quote(db=self.db, quote=quote)
return quote

# TODO: generate secret with BIP39 (seed and specific derivation + counter)
async def get_quote_ephemeral_key(self) -> Union[PrivateKey, None]:
"""Creates a secret key for a quote
"""
if not self.mint_info:
await self.load_mint_info()
assert self.mint_info.nuts
nut19 = self.mint_info.nuts.get(QUOTE_SIGNATURE_NUT, None)
if nut19 and nut19["supported"]:
return PrivateKey()
else:
return None

def split_wallet_state(self, amount: int) -> List[int]:
"""This function produces an amount split for outputs based on the current state of the wallet.
Its objective is to fill up the wallet so that it reaches `n_target` coins of each amount.
Expand Down

0 comments on commit 3b1109b

Please sign in to comment.