1
0

add static payment key

* in order to be able to sweep to_remote in an onchain backup scenario
  we need to retain the private key for the payment_basepoint
* to facilitate the above, we open a channel derived from a static
  secret (tied to the wallet seed), the static_payment_key combined with
the funding pubkey (multisig_key), which we can restore from the channel
closing transaction
This commit is contained in:
bitromortac
2021-09-22 11:12:38 +02:00
committed by ThomasV
parent 3951e07c53
commit 22f5ff0d0e
4 changed files with 43 additions and 8 deletions

View File

@@ -212,7 +212,6 @@ class LocalConfig(ChannelConfig):
@classmethod
def from_seed(cls, **kwargs):
channel_seed = kwargs['channel_seed']
static_remotekey = kwargs.pop('static_remotekey')
node = BIP32Node.from_rootseed(channel_seed, xtype='standard')
keypair_generator = lambda family: generate_keypair(node, family)
kwargs['per_commitment_secret_seed'] = keypair_generator(LnKeyFamily.REVOCATION_ROOT).privkey
@@ -220,11 +219,23 @@ class LocalConfig(ChannelConfig):
kwargs['htlc_basepoint'] = keypair_generator(LnKeyFamily.HTLC_BASE)
kwargs['delayed_basepoint'] = keypair_generator(LnKeyFamily.DELAY_BASE)
kwargs['revocation_basepoint'] = keypair_generator(LnKeyFamily.REVOCATION_BASE)
if static_remotekey:
static_remotekey = kwargs.pop('static_remotekey')
static_payment_key = kwargs.pop('static_payment_key')
if static_payment_key:
# We derive the payment_basepoint from a static secret (derived from
# the wallet seed) and a public nonce that is revealed
# when the funding transaction is spent. This way we can restore the
# payment_basepoint, needed for sweeping in the event of a force close.
kwargs['payment_basepoint'] = derive_payment_basepoint(
static_payment_secret=static_payment_key.privkey,
funding_pubkey=kwargs['multisig_key'].pubkey
)
elif static_remotekey: # we automatically sweep to a wallet address
kwargs['payment_basepoint'] = OnlyPubkeyKeypair(static_remotekey)
else:
# we expect all our channels to use option_static_remotekey, so ending up here likely indicates an issue...
kwargs['payment_basepoint'] = keypair_generator(LnKeyFamily.PAYMENT_BASE)
return LocalConfig(**kwargs)
def validate_params(self, *, funding_sat: int, config: 'SimpleConfig', peer_features: 'LnFeatures') -> None:
@@ -586,6 +597,16 @@ def derive_blinded_privkey(basepoint_secret: bytes, per_commitment_secret: bytes
return int.to_bytes(sum, length=32, byteorder='big', signed=False)
def derive_payment_basepoint(static_payment_secret: bytes, funding_pubkey: bytes) -> Keypair:
assert isinstance(static_payment_secret, bytes)
assert isinstance(funding_pubkey, bytes)
payment_basepoint = ecc.ECPrivkey(sha256(static_payment_secret + funding_pubkey))
return Keypair(
pubkey=payment_basepoint.get_public_key_bytes(),
privkey=payment_basepoint.get_secret_bytes()
)
def make_htlc_tx_output(
amount_msat, local_feerate, revocationpubkey, local_delayedpubkey, success, to_self_delay,
) -> Tuple[bytes, PartialTxOutput]: