Avatar
Rusty Russell
f1725586a402c06aec818d1478a45aaa0dc16c7a9c4869d97c350336d16f8e43
Lead Core Lightning, Standards Wrangler, Bitcoin Script Restoration ponderer, coder. Full time employed on Free and Open Source Software since 1998. Joyous hacking with others for over 25 years.

As I've aged, I have come to terms with people not asking my permission or seeking my approval.

Surprisingly often, my disapproval was just glass shards I was feeding myself. So I stopped.

Replying to Avatar calle

Good point: where are the hot gay Bitcoiners at?

You're right! I should have said "a significant number".

Most of my friends are non-Bitcoiners. A significant fraction are non-binary, an even larger number are neurodiverse, and many are half my age: a great variety of fascinatingly different humans!

It's OK to be weird, and it makes our world more interesting. If that makes me outside someone's "ethos of Bitcoin" I think they misunderstand what Bitcoin is for.

#cln #dev

Finally catching up with the latest BOLT12 spec, and damn, Phoenix just announced BIP 353 support. Gotta code faster!

You should seriously consider this. Annoying as it is to throw away working code, this code is *annoying* in a way few things in the specs are.

I really wish there was a way to use partial onions for this instead, but I can't make it work with the addition of the payload at the end (and you'd have to use exact values down each path, but that's probably ok).

Even my new code doesn't do padding, delaying, dummy hops or fake node IDs like everyone would like. That will probably be in 24.11...

#cln #dev

Wrapping up the great blinded path catchup, I hit a snag. Paying an invoice where we ourselves are nominated as the head of the blinded path. I solved this case elegantly for onion messages, but actual payments are not so easy.

In an ideal world, our code would have been written so we could have either the RPC or an incoming HTLC trigger this code. But unwrapping and forwarding are only written for incoming HTLCs, and reworking all that is a major task. I may revisit this one day, as such code would transparently allow self-payment which currently has a special path.

So instead we are going to have another special path for this case :( I thought about simply unwrapping the onion inside the pay plugin for this, but it requires ECDH using the node key which we don't expose through RPC (and I'm reluctant to expose).

Hoping to finish soon as this is a large part of getting offers to production ready (vs the current experimental config option).

Replying to Avatar jb55

why do current zaps need custodians or middlemen? It’s slightly easier but you still need to run a node which most people won’t do.

I think the “bolt12 will make things more decentralized” meme is a bit over-optimistic. The only thing it does is not require a web server, but thats not even the hardest part, and is even not needed because of services like https://sendsats.lol which i use for my noncustodial zaps.

Also, how do web clients fetch the invoice? Even if you use my lnsocket library, you still need a publicly routable node to serve the offer request, then your back to nwc invoice fetching or something which is way better for decentralization nostr:note1nflxn2l39t5phz7eqnc2u076jgs00f9kw0xxgdqcdwy86szv5hgq0fuwqu

You don't need to *ask* a public node to route for you, they can't really tell you're using them this way.

The web->LN issue is real: no certs, no web for you!

Getting an invoice without waking the node seems to require PTLCs.

Usually found at the intersection of any fan base and bitcoin. For example, why Apple is going to get into Bitcoin...

There's a thing I saw often in the early Linux days and still see in Bitcoin communities. People discover Bitcoin and try to wedge it into their existing special interest and extol the crossover as a discovery (rather than a construction).

I call this "Bitcoin fan-fiction". It's weird, awkward and very very human. It's also usually very easy to spot in others, never in ourselves 💛

Yep, spec changed recently, but the change isn't in CLN yet.

Embarrassing, but the arguments for the change were quite compelling*. And it's the reason the final spec has not been merged.

*It also happens to reduce the size of the minimal BOLT12 tattoo! Why? Um, no reason...

Lunduke should always be taken with a large pinch of salt...

You don't need to reach to philosophy to reject this. There was a deliberate decision early on to support the network via usage fees, not via holding fees: otherwise some non-zero inflation would have been the cleanest solution.

It does, of course, imply a third stage of Bitcoin's economic journey, which creates uncertainty. But you can't say people weren't warned!

https://rusty-lightning.medium.com/the-three-economic-eras-of-bitcoin-d43bf0cf058a

#dev #CLN

I've spent the last few workdays completely reworking our onion message code. This was scattered in various places and I wanted to unify it, and also written several years ago and I'd forgotten how the protocol actually works!

onion messages are *double* encrypted; this is the main source of confusion! At the high layer, they're a series of nested encrypted calls ("onionmsg_tlv" in the BOLT 4 spec), so each recipient decrypts and hands it on: this is exactly the same as we use for payment information. But inside that is *another* encrypted blob (onionmsg_tlv.encrypted_recipient_data), which requires a tweak which was handed to you alongside the onion, for you to decrypt (into an "encrypted_data_tlv"). Inside that is all the information about where to send next, any restrictions, and allows you to calculate the *next* tweak to hand on (it can also override the next tweak).

The double encryption is necessary because there are *three* actors here: Alice wants Bob to send her a message, without revealing her identity. So she gives Bob a "blinded path" which goes via Charlie: this path contains Charlie's pubkey (where to start the path), a blinding tweak, and two encrypted blobs for Alice to put into each layer of the onion message. The first an encrypted blob which Charlie can read, which contains her pubkey so he knows where to send it next. The second is her own, and contains a secret specific to the purpose of this message, so Bob can't play games trying to use this blinded path for anything else ("hey, are you the same node as this previous payment?") or use a different blinded path for this purpose. She can also add dummy hops (we don't yet), which she will simply absorb, to obscure the path length from Bob. You can add padding to make the hops indistinguishable (we don't yet).

Bob puts the actual stuff he wants to send Alice into the final onion call (often including his own blinded reply path!), along with the encrypted blob.

Importantly, even if Bob were sending a message *not through a blinded path* he would use the same double-encrypted format: that's so Charlie can't tell whether a blinded path is being used or not, even though it's slightly less efficient. Crypto is cheap these days, too.

Now, if Alice gives Bob a blinded path to Charlie and Charlie is Bob's peer, he can simply send the onion and the first blinding tweak to Charlie. But if Alice needs to send the message via Dave to Charlie, she needs to prepend a step. That's not quite possible, naively, because blinding tweaks are generated *forwards*, and she needs Charlie to get the right blinding tweak from Dave, and Alice has no way of making that happen. So inside Dave's encrypted blob, she uses next_blinding_override to tell Dave to hand that blinding override to Charlie instead of the normal one. I just implemented this for Core Lightning (previously we would simply connect to the first node, which is privacy-compromising and should only be done as a last resort).

These blinded paths have some nice properties: you can't use part of them (you don't know the blinding factor except for the first one, so you can't start in the middle, and you can't replace any data), you need to use all of them. They can contain timelimits to avoid easy probing, too: a classic measure would be to see if the path fails when a given node is down, but that takes time. The spec insists all errors within the blinded path are the same, and originate from the entry: this loses some analytical power on failure, but makes probing harder. The entry point is supposed to add a random delay (we don't yet!). There may still be implementation differences, but they're hard for Bob to probe (and Alice doesn't need to, as she set up the path).

ChaumedToMeetYou

BlindedByTheSats

EllipticalTrainer (for Signet)

SatoshiMince

The lesson of sigops was exactly that limits should be based on weight, so you don't need to optimize for two different constraints on block construction.

Same deal here: more vbytes, more varops budget.