How to recover funds from a force-closed Lnd lightning channel?
In c-lightning the per commitment point is derived from the hsm_secret using per_commit_point from:


The node id / public key (can be found with listfunds, until the channel is purged some time after closing)
The channel database id (can be found with cat ~/.lightning/debug.log | grep $node_id), shown as chan #$node_id
The commitment number (0 when opening the channel, increases during fee negotiations and other channel updates, |  grep commit)


We care about the commitment point, not the secret, because the private key we need is derived as follows:

privkey = basepoint_secret + SHA256(per_commitment_point || basepoint)


I created a tool for c-lightning to dump this point (with help from @cdecker): https://github.com/ElementsProject/lightning/pull/3115

Back to Lnd... One easy place to dump a private key is in the lnwallet walletinfo command. Add something like this to commands.go:



basePointSecret, err := keyRing.DerivePrivKey(keychain.KeyDescriptor{
  KeyLocator: keychain.KeyLocator{
    Family: keychain.KeyFamilyPaymentBase,
    Index:  0, // Same commitment index as used in c-lightning 
  },
})

// Parse per_commitment_point dumped by c-lightning:
bytes, err := hex.DecodeString(".........")
commitPoint, err := btcec.ParsePubKey(bytes, btcec.S256())

// Obtain SHA256(per_commitment_point || basepoint)
h := sha256.New()
h.Write(commitPoint.SerializeCompressed())
h.Write(basePointSecret.PubKey().SerializeCompressed())
commitTweak := h.Sum(nil)

// Obtain and dump private key
tweakedPrivkey := TweakPrivKey(basePointSecret, commitTweak)
commitmentWif, err := btcutil.NewWIF(tweakedPrivkey, &amp;chaincfg.MainNetParams, true)

fmt.Printf("Dump commitment priv key: %s\n", commitmentWif)


Where TweakPrivKey() is lifted from script_utils.

Import the resulting private key into Bitcoin Core et voila!