Rusty Russell's avatar
Rusty Russell
rusty@rusty.ozlabs.org
npub179e9...lz4s
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.
#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).
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 ๐Ÿ’›
#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).
#Bitcoin #dev #GSR At in Austin I presented my work on restoring Bitcoin Script. Script had an emergency amputation in 2010 as there were no limits on resource consumption; restoring it means solving this problem. My proposal is a runtime limit, similar to Taproot's runtime sigops limit, called "varops". How much you get depends on your transaction size (ie how much you paid), similar to sigops. But how much should operations cost? I had a cost model based on "worst-case bytes touched" for each operation. I've spent the last few weeks doing increasingly precise micro-benchmarks on my laptop, my build machine, and various Raspberry Pi. There's bad news, and good news....
#dev #CLN One of the fun things after a release is that I sweep the code and remove things which are now past the end of their deprecation cycle, and then update to the latest BOLT specs. The former is usually trivial (this time there were only two things to remove, and nobody will care). The latter can be more interesting, and was. Our code contains quotes from the BOLT they are implementing, so when we update the version it reports what has changed. Sometimes it's merely a typo fix, but since last release we actually made a pile of old features ASSUMED. This includes "option_static_remotekey" which we supported in CLN since January 2019 release, meaning you will only see channels without this if they were opened more than 5 years ago. We still support these existing channels, but all support was removed for opening new ones. The other option is "option_anchor_outputs": we were the only ones to ever deploy this, and then only in experimental mode, because zero-fee anchors quickly replaced it. Unfortunate to I don't know how many (if any!) such channels there are! So what do we do about existing channels? I can enable the currently-experimental code to migrate such channels, which works if both ends are CLN. But it's not clear how much further I should go: my spec proposal for upgrade has been in limbo for years, and at some point it's far cheaper to pay a handful of people to reopen their channels than it is to do the engineering required for migration. It's a few versions away yet, but at some point we will have to refuse to upgrade if the user has such a channel, in the hope they will contact us if it happens.
Great podcast: I gain thoughtful insight from an expert in a field I'm not an expert on. Good podcast: I gain minor insight into how to discuss a field of my expertise. Bad podcast: Someone who knows no more than me about the subject. It's ok to not know something! But I wouldn't go on a podcast and discuss AI. Or business cases for Bitcoin, nuclear power, economic incentives, politics, nostr...
Sneak peeking at new bolt12.org re-wrought by @Spiral (especially Stephen DeLorme, Brandon Lucas and the Bitcoin Design Community incl @HBerkoe). So.... pretty....
BTW "It is not possible to delegate the work without delegating the key (supposedly)" is wrong: you can definitely do this! Various vanity address generators did this back in the day, for Bitcoin.
There are always many things you can do with your time, but implementing silent payments (https://github.com/bitcoin/bips/blob/master/bip-0352.mediawiki) for Core Lightning is rising in my to-do list. Unfortunately, we are all PSBT internally, so we need support so we can receive, which the authors argue (sensibly) should be the first priority for wallets. There's a delving post on this, so I did my bit by annoying Ava Chow into looking at it. We can probably hack in some experimental thing if we need for now, but proper support on libwally would smooth the path for Blockstream Green in future, which frankly is a much bigger win than CLN support. Looking forward to the day when they're not "silent payment addresses" but simply "Bitcoin addresses".
One day I will reach the pinnacle of nostr technical capabilities, and be able to access my npub.cash funds. Right, @calle?
โ†‘