lnpeer: new payment secret, derived without preimage.
(this is needed for hold invoices)
This commit is contained in:
@@ -1826,8 +1826,12 @@ class Peer(Logger):
|
|||||||
raise exc_incorrect_or_unknown_pd
|
raise exc_incorrect_or_unknown_pd
|
||||||
preimage = self.lnworker.get_preimage(htlc.payment_hash)
|
preimage = self.lnworker.get_preimage(htlc.payment_hash)
|
||||||
if payment_secret_from_onion:
|
if payment_secret_from_onion:
|
||||||
if payment_secret_from_onion != derive_payment_secret_from_payment_preimage(preimage):
|
expected_payment_secrets = [self.lnworker.get_payment_secret(htlc.payment_hash)]
|
||||||
log_fail_reason(f'incorrect payment secret {payment_secret_from_onion.hex()} != {derive_payment_secret_from_payment_preimage(preimage).hex()}')
|
if preimage:
|
||||||
|
# legacy secret for old invoices
|
||||||
|
expected_payment_secrets.append(derive_payment_secret_from_payment_preimage(preimage))
|
||||||
|
if payment_secret_from_onion not in expected_payment_secrets:
|
||||||
|
log_fail_reason(f'incorrect payment secret {payment_secret_from_onion.hex()} != {expected_payment_secrets[0].hex()}')
|
||||||
raise exc_incorrect_or_unknown_pd
|
raise exc_incorrect_or_unknown_pd
|
||||||
invoice_msat = info.amount_msat
|
invoice_msat = info.amount_msat
|
||||||
if not (invoice_msat is None or invoice_msat <= total_msat <= 2 * invoice_msat):
|
if not (invoice_msat is None or invoice_msat <= total_msat <= 2 * invoice_msat):
|
||||||
|
|||||||
@@ -1538,6 +1538,7 @@ class LnKeyFamily(IntEnum):
|
|||||||
REVOCATION_ROOT = 5 | BIP32_PRIME
|
REVOCATION_ROOT = 5 | BIP32_PRIME
|
||||||
NODE_KEY = 6
|
NODE_KEY = 6
|
||||||
BACKUP_CIPHER = 7 | BIP32_PRIME
|
BACKUP_CIPHER = 7 | BIP32_PRIME
|
||||||
|
PAYMENT_SECRET_KEY = 8 | BIP32_PRIME
|
||||||
|
|
||||||
|
|
||||||
def generate_keypair(node: BIP32Node, key_family: LnKeyFamily) -> Keypair:
|
def generate_keypair(node: BIP32Node, key_family: LnKeyFamily) -> Keypair:
|
||||||
|
|||||||
@@ -217,6 +217,7 @@ class LNWorker(Logger, EventListener, NetworkRetryManager[LNPeerAddr]):
|
|||||||
self.lock = threading.RLock()
|
self.lock = threading.RLock()
|
||||||
self.node_keypair = generate_keypair(BIP32Node.from_xkey(xprv), LnKeyFamily.NODE_KEY)
|
self.node_keypair = generate_keypair(BIP32Node.from_xkey(xprv), LnKeyFamily.NODE_KEY)
|
||||||
self.backup_key = generate_keypair(BIP32Node.from_xkey(xprv), LnKeyFamily.BACKUP_CIPHER).privkey
|
self.backup_key = generate_keypair(BIP32Node.from_xkey(xprv), LnKeyFamily.BACKUP_CIPHER).privkey
|
||||||
|
self.payment_secret_key = generate_keypair(BIP32Node.from_xkey(xprv), LnKeyFamily.PAYMENT_SECRET_KEY).privkey
|
||||||
self._peers = {} # type: Dict[bytes, Peer] # pubkey -> Peer # needs self.lock
|
self._peers = {} # type: Dict[bytes, Peer] # pubkey -> Peer # needs self.lock
|
||||||
self.taskgroup = OldTaskGroup()
|
self.taskgroup = OldTaskGroup()
|
||||||
self.listen_server = None # type: Optional[asyncio.AbstractServer]
|
self.listen_server = None # type: Optional[asyncio.AbstractServer]
|
||||||
@@ -1824,9 +1825,7 @@ class LNWallet(LNWorker):
|
|||||||
routing_hints, trampoline_hints = self.calc_routing_hints_for_invoice(amount_msat, channels=channels)
|
routing_hints, trampoline_hints = self.calc_routing_hints_for_invoice(amount_msat, channels=channels)
|
||||||
self.logger.info(f"creating bolt11 invoice with routing_hints: {routing_hints}")
|
self.logger.info(f"creating bolt11 invoice with routing_hints: {routing_hints}")
|
||||||
invoice_features = self.features.for_invoice()
|
invoice_features = self.features.for_invoice()
|
||||||
payment_preimage = self.get_preimage(payment_hash)
|
payment_secret = self.get_payment_secret(payment_hash)
|
||||||
if payment_preimage is None: # e.g. when export/importing requests between wallets
|
|
||||||
raise Exception("missing preimage for payment_hash")
|
|
||||||
amount_btc = amount_msat/Decimal(COIN*1000) if amount_msat else None
|
amount_btc = amount_msat/Decimal(COIN*1000) if amount_msat else None
|
||||||
if expiry == 0:
|
if expiry == 0:
|
||||||
expiry = LN_EXPIRY_NEVER
|
expiry = LN_EXPIRY_NEVER
|
||||||
@@ -1843,12 +1842,15 @@ class LNWallet(LNWorker):
|
|||||||
+ routing_hints
|
+ routing_hints
|
||||||
+ trampoline_hints,
|
+ trampoline_hints,
|
||||||
date=timestamp,
|
date=timestamp,
|
||||||
payment_secret=derive_payment_secret_from_payment_preimage(payment_preimage))
|
payment_secret=payment_secret)
|
||||||
invoice = lnencode(lnaddr, self.node_keypair.privkey)
|
invoice = lnencode(lnaddr, self.node_keypair.privkey)
|
||||||
pair = lnaddr, invoice
|
pair = lnaddr, invoice
|
||||||
self._bolt11_cache[payment_hash] = pair
|
self._bolt11_cache[payment_hash] = pair
|
||||||
return pair
|
return pair
|
||||||
|
|
||||||
|
def get_payment_secret(self, payment_hash):
|
||||||
|
return sha256(sha256(self.payment_secret_key) + payment_hash)
|
||||||
|
|
||||||
def create_payment_info(self, *, amount_msat: Optional[int], write_to_disk=True) -> bytes:
|
def create_payment_info(self, *, amount_msat: Optional[int], write_to_disk=True) -> bytes:
|
||||||
payment_preimage = os.urandom(32)
|
payment_preimage = os.urandom(32)
|
||||||
payment_hash = sha256(payment_preimage)
|
payment_hash = sha256(payment_preimage)
|
||||||
|
|||||||
@@ -138,6 +138,7 @@ class MockLNWallet(Logger, EventListener, NetworkRetryManager[LNPeerAddr]):
|
|||||||
Logger.__init__(self)
|
Logger.__init__(self)
|
||||||
NetworkRetryManager.__init__(self, max_retry_delay_normal=1, init_retry_delay_normal=1)
|
NetworkRetryManager.__init__(self, max_retry_delay_normal=1, init_retry_delay_normal=1)
|
||||||
self.node_keypair = local_keypair
|
self.node_keypair = local_keypair
|
||||||
|
self.payment_secret_key = os.urandom(256) # does not need to be deterministic in tests
|
||||||
self._user_dir = tempfile.mkdtemp(prefix="electrum-lnpeer-test-")
|
self._user_dir = tempfile.mkdtemp(prefix="electrum-lnpeer-test-")
|
||||||
self.config = SimpleConfig({}, read_user_dir_function=lambda: self._user_dir)
|
self.config = SimpleConfig({}, read_user_dir_function=lambda: self._user_dir)
|
||||||
self.network = MockNetwork(tx_queue, config=self.config)
|
self.network = MockNetwork(tx_queue, config=self.config)
|
||||||
@@ -239,6 +240,7 @@ class MockLNWallet(Logger, EventListener, NetworkRetryManager[LNPeerAddr]):
|
|||||||
full_path=full_path)]
|
full_path=full_path)]
|
||||||
|
|
||||||
get_payments = LNWallet.get_payments
|
get_payments = LNWallet.get_payments
|
||||||
|
get_payment_secret = LNWallet.get_payment_secret
|
||||||
get_payment_info = LNWallet.get_payment_info
|
get_payment_info = LNWallet.get_payment_info
|
||||||
save_payment_info = LNWallet.save_payment_info
|
save_payment_info = LNWallet.save_payment_info
|
||||||
set_invoice_status = LNWallet.set_invoice_status
|
set_invoice_status = LNWallet.set_invoice_status
|
||||||
|
|||||||
Reference in New Issue
Block a user