feat: generate keys
This commit is contained in:
parent
f317a7cb2d
commit
b7cd0f4d45
52
lnbits/extensions/cashu/core/secp.py
Normal file
52
lnbits/extensions/cashu/core/secp.py
Normal file
|
@ -0,0 +1,52 @@
|
|||
from secp256k1 import PrivateKey, PublicKey
|
||||
|
||||
|
||||
# We extend the public key to define some operations on points
|
||||
# Picked from https://github.com/WTRMQDev/secp256k1-zkp-py/blob/master/secp256k1_zkp/__init__.py
|
||||
class PublicKeyExt(PublicKey):
|
||||
def __add__(self, pubkey2):
|
||||
if isinstance(pubkey2, PublicKey):
|
||||
new_pub = PublicKey()
|
||||
new_pub.combine([self.public_key, pubkey2.public_key])
|
||||
return new_pub
|
||||
else:
|
||||
raise TypeError("Cant add pubkey and %s" % pubkey2.__class__)
|
||||
|
||||
def __neg__(self):
|
||||
serialized = self.serialize()
|
||||
first_byte, remainder = serialized[:1], serialized[1:]
|
||||
# flip odd/even byte
|
||||
first_byte = {b"\x03": b"\x02", b"\x02": b"\x03"}[first_byte]
|
||||
return PublicKey(first_byte + remainder, raw=True)
|
||||
|
||||
def __sub__(self, pubkey2):
|
||||
if isinstance(pubkey2, PublicKey):
|
||||
return self + (-pubkey2)
|
||||
else:
|
||||
raise TypeError("Can't add pubkey and %s" % pubkey2.__class__)
|
||||
|
||||
def mult(self, privkey):
|
||||
if isinstance(privkey, PrivateKey):
|
||||
return self.tweak_mul(privkey.private_key)
|
||||
else:
|
||||
raise TypeError("Can't multiply with non privatekey")
|
||||
|
||||
def __eq__(self, pubkey2):
|
||||
if isinstance(pubkey2, PublicKey):
|
||||
seq1 = self.to_data()
|
||||
seq2 = pubkey2.to_data()
|
||||
return seq1 == seq2
|
||||
else:
|
||||
raise TypeError("Can't compare pubkey and %s" % pubkey2.__class__)
|
||||
|
||||
def to_data(self):
|
||||
return [self.public_key.data[i] for i in range(64)]
|
||||
|
||||
|
||||
# Horrible monkeypatching
|
||||
PublicKey.__add__ = PublicKeyExt.__add__
|
||||
PublicKey.__neg__ = PublicKeyExt.__neg__
|
||||
PublicKey.__sub__ = PublicKeyExt.__sub__
|
||||
PublicKey.mult = PublicKeyExt.mult
|
||||
PublicKey.__eq__ = PublicKeyExt.__eq__
|
||||
PublicKey.to_data = PublicKeyExt.to_data
|
12
lnbits/extensions/cashu/mint.py
Normal file
12
lnbits/extensions/cashu/mint.py
Normal file
|
@ -0,0 +1,12 @@
|
|||
|
||||
from .crud import get_cashu
|
||||
from .mint_helper import derive_keys, derive_pubkeys
|
||||
|
||||
|
||||
def get_pubkeys(xpriv: str):
|
||||
"""Returns public keys for possible amounts."""
|
||||
|
||||
keys = derive_keys(xpriv)
|
||||
pub_keys = derive_pubkeys(keys)
|
||||
|
||||
return {a: p.serialize().hex() for a, p in pub_keys.items()}
|
22
lnbits/extensions/cashu/mint_helper.py
Normal file
22
lnbits/extensions/cashu/mint_helper.py
Normal file
|
@ -0,0 +1,22 @@
|
|||
import hashlib
|
||||
from typing import List, Set
|
||||
from .core.secp import PrivateKey, PublicKey
|
||||
|
||||
# todo: extract const
|
||||
MAX_ORDER = 64
|
||||
|
||||
def derive_keys(master_key: str):
|
||||
"""Deterministic derivation of keys for 2^n values."""
|
||||
return {
|
||||
2
|
||||
** i: PrivateKey(
|
||||
hashlib.sha256((str(master_key) + str(i)).encode("utf-8"))
|
||||
.hexdigest()
|
||||
.encode("utf-8")[:32],
|
||||
raw=True,
|
||||
)
|
||||
for i in range(MAX_ORDER)
|
||||
}
|
||||
|
||||
def derive_pubkeys(keys: List[PrivateKey]):
|
||||
return {amt: keys[amt].pubkey for amt in [2**i for i in range(MAX_ORDER)]}
|
|
@ -15,7 +15,8 @@ from lnbits.core.views.api import api_payment
|
|||
from lnbits.decorators import WalletTypeInfo, get_key_type, require_admin_key
|
||||
|
||||
from . import cashu_ext
|
||||
from .ledger import get_pubkeys, request_mint, mint
|
||||
from .ledger import request_mint, mint
|
||||
from .mint import get_pubkeys
|
||||
|
||||
from .crud import (
|
||||
create_cashu,
|
||||
|
@ -35,6 +36,11 @@ from .models import (
|
|||
PayLnurlWData
|
||||
)
|
||||
|
||||
########################################
|
||||
#################MINT CRUD##############
|
||||
########################################
|
||||
|
||||
# todo: use /mints
|
||||
@cashu_ext.get("/api/v1/cashus", status_code=HTTPStatus.OK)
|
||||
async def api_cashus(
|
||||
all_wallets: bool = Query(False), wallet: WalletTypeInfo = Depends(get_key_type)
|
||||
|
@ -83,6 +89,9 @@ async def api_cashu_delete(
|
|||
raise HTTPException(status_code=HTTPStatus.NO_CONTENT)
|
||||
|
||||
|
||||
########################################
|
||||
#################????###################
|
||||
########################################
|
||||
@cashu_ext.post("/api/v1/cashus/{cashu_id}/invoices", status_code=HTTPStatus.CREATED)
|
||||
async def api_cashu_create_invoice(
|
||||
amount: int = Query(..., ge=1), tipAmount: int = None, cashu_id: str = None
|
||||
|
@ -192,10 +201,16 @@ async def api_cashu_check_invoice(cashu_id: str, payment_hash: str):
|
|||
#################MINT###################
|
||||
########################################
|
||||
|
||||
@cashu_ext.get("/keys")
|
||||
def keys(cashu_id: str):
|
||||
@cashu_ext.get("/api/v1/mint/keys/{cashu_id}", status_code=HTTPStatus.OK)
|
||||
async def keys(cashu_id: str = Query(False), wallet: WalletTypeInfo = Depends(get_key_type)):
|
||||
"""Get the public keys of the mint"""
|
||||
return get_pubkeys(cashu_id)
|
||||
print('############################')
|
||||
mint = await get_cashu(cashu_id)
|
||||
if mint is None:
|
||||
raise HTTPException(
|
||||
status_code=HTTPStatus.NOT_FOUND, detail="Mint does not exist."
|
||||
)
|
||||
return get_pubkeys(mint.prvkey)
|
||||
|
||||
|
||||
@cashu_ext.get("/mint")
|
||||
|
|
Loading…
Reference in New Issue
Block a user