My inspiration was the realization that Lightning nodes can do whatever they want with HTLCs they accept from others. The onion they receive contains the next channel which they should forward that payment to, but they don't have to forward that if they don't want. In fact, it doesn't even have to be a real channel. That channel id could be used to encode a different kind of information.
What it does
This is a c-lightning plugin that generates invoices from its own node with route hints to private channels. It includes these route hints in the invoices it generates, but these private channels and corresponding private nodes don't actually exist.
Then it uses the
htlc_accepted hook to read the information about the next route. If it's one of the "shadow" channels it knows how to build the preimage necessary to resolve that HTLC from the channel id itself, keeping the money and resolving the payment for the sender.
The good thing is that is hides the node id of the receiver -- not completely, as it must appear in the route hints, but at least it's not obvious that it is the final node, instead the final node appears to be some random private node no one will ever know if exists or not.
How I built it
I've used https://github.com/fiatjaf/lightningd-gjson-rpc, the c-lightning plugin docs, the https://godoc.org/github.com/lightningnetwork/lnd/zpay32 library and a bunch of guessing and luck.
Challenges I ran into
Got some pending unresolved payments while writing it and was afraid my channels would all get closed (becase I was doing all on mainnet) but then everything turned out to be ok.
What's next for shadows plugin
This is the biggest part. I plan to integrate this plugin with some modifications into https://t.me/lntxbot so each bot user can have its own (fake) node id when generating invoices and hide the fact that they're using a custodial wallet.
The next step would be plug a custodial accounts database admin to it and turn it into an lndhub plugin so people could just throw a binary in their c-lightning nodes and instantly begin powering BlueWallets of their friends and families, and all them would appear to the external world as if they were using their own private nodes and not a custodial server.