Re: [Lightning-dev] Deriving channel keys deterministically from seed, musig, and channel establishment v2
Hi SomberNight, I started a similar discussion less than a year ago on the list. The idea I put forward works fine with MuSig and taproot. https://lists.linuxfoundation.org/pipermail/lightning-dev/2020-December/002907.html The idea was considered for channel establishment v2 but in the end there were various objections to it becoming specified as it forces implementations to handle keys in a certain way. You can still do it informally though by fixing your funding pubkey to be derived from the Diffie-Hellman key of the two node ids. This makes the funding public keys a (secret) deterministic function of the two node ids without making a privacy leak. FWIW I still think this is a good idea but in hindsight I think the objections to it being mandatory are valid. Cheers, LL On Sat, 18 Sept 2021 at 02:14, SomberNight via Lightning-dev < lightning-dev@lists.linuxfoundation.org> wrote: > Hi all, > > TL;DR: an approach is described how to derive channel keys > deterministically that allows certain forms of recovery from just > a seed, that works today. This approach however will no longer work > with e.g. MuSig key aggregation in the future. An idea for a proposal > is given how the channel-open flow (e.g. as part of channel v2) could be > changed to make a similar approach work independent of key aggregation. > > - > > While implementing anchor output support in Electrum, we have realised > one difficulty is to do with the remote-force-close case where the > to_remote output is no longer a simple p2wpkh. > > Currently, pre-anchor-support, Electrum sets option_static_remotekey > to required (feature bit 12), and we restrict lightning usage to wallets > that derive p2wpkh addresses, and payment_basepoint is set > to a bip32-derived pubkey that corresponds to a wallet address. > Hence, if a user were to restore from seed words, and their channel > counterparty force closed their channel, the to_remote output of the > broadcast commitment tx would directly pay to the user's wallet. > That is, in many typical scenarios, funds are not lost when restoring > from seed. > > (Also, if we are the channel-funder/opener, it is easy to find the > funding transaction, just by testing txs in the wallet history. > Further, for the cases we are the channel-funder/opener, > there is a setting to put an OP_RETURN in the funding tx, which stores > the nodeid of the counterparty, allowing us to identify who to contact > to get the channel closed. > Also, we are (ab)using dataloss_protect to ask the remote > to force-close when restoring from seed, so the user does not even have > to wait for an arbitrarily long time.) > > With anchors, the to_remote is now a p2wsh that involves a CSV, > and we cannot easily make this script correspond to a wallet address, > i.e. we lose the property that the remote-force-close pays directly > to a wallet address. > > So, the problem we would like to solve, is: > - having seed words > - having access to blockchain data > - somehow having identified our channel counterparties (node IDs), > and our channels with them (funding outpoints) > - and assuming we can get the remote to do a force-close > --> we would like to be able to spend the to_remote output > > Solutions: > > 1) Naively, we could just derive a static key to be used as > payment_basepoint, reused between all our channels, and watch the > single resulting p2wsh script on-chain. > Clearly this has terrible privacy implications. > > 2) Or, we could derive a new bip32 chain/sequence of pubkeys > used as payment_basepoint for channels, and watch these p2wsh scripts, > with a gap limit. > Particularly the gap limit part makes this undesirable though > (just consider having more than "gap limit" channels open and restoring > from seed). > > Instead, it seems desirable to see whether we can extract some entropy > from the blockchain, and use that as a nonce to be combined with a > static private secret derived from our seed. > We could extract data either from the funding tx, or from the > remote-commitment-transaction that spent the funding output. > > 3) We exploit the fact that the funding output uses a > 2of2 OP_CHECKMULTISIG script composed of the funding pubkeys of > each party. The funding pubkey itself can be used as a nonce, and > it can be recovered from the witness of the commitment tx. > The privkey for payment_basepoint can then be derived as e.g. > hash(bip32_derive(seed, HARDCODED_PATH) + funding_pubkey). > > In fact (3) is not novel at all: eclair has been deriving > all their channel keys like this [0] for some time, from > a static seed-based secret combined with the funding_pubkey as nonce, > and generating the funding_privkey from ~os.urandom. > > Electrum will likely use (3) at least for the payment_basepoint, > as part of adapting to anchors. > > - > > Note that the idea (3) relies on recovering the funding_pubkey from > the witness of the spending transaction, which will break in the future > if the funding
Re: [Lightning-dev] Deriving channel keys deterministically from seed, musig, and channel establishment v2
Good morning SomberNight, > Good morning ZmnSCPxj, > > > > Solutions: > > > > > > 1. Naively, we could just derive a static key to be used as > > > payment_basepoint, reused between all our channels, and watch the > > > single resulting p2wsh script on-chain. > > > Clearly this has terrible privacy implications. > > > > > > > If the only problem is horrible privacy, and you have an > > `OP_RETURN`identifying the channel counterparty node id anyway, would it > > not be possible to tweak this for each channel? > > static_payment_basepoint_key + hash(seed | counterparty_node_id) > > This (should) result in a unique key for each counterparty, yet each > > individual counterparty cannot predict this tweak (and break your privacy > > by deriving the `static_payment_basepoint_key * G`). > > The OP_RETURN containing the encrypted counterparty node id > is only an option, ideally it should not be required. > > Also, your proposal needs a counter too, to avoid reuse between multiple > channels with the same counterparty. This counter is actually quite > problematic as users should be able to open new channels after > restoring from seed, which means they need to be able to figure out > the last value of the counter reliably, which seems potentially > problematic, so actually this might have to be a random nonce that is > wide enough to make collisions unlikely... (potentially taking up > valuable blockchain space in the OP_RETURN) Yes, that does seem to be somewhat problematic. As to your proposal to change the open v2 protocol --- as I understand it, the current channel establishment v2 is already deployed in production on C-Lightning nodes, so at minimum your proposed extension should probably use different feature bits and message IDs, I think. CCing lisa for comment. In any case, I think changing the actual commitment scheme to use MuSig1/MuSig2/MuSig-DN is lower priority than deploying PTLCs (and PTLCs can be used perfectly fine with the current commitment scheme, since you can spend from SegWitv1 P2WPKH to P2TR perfectly fine). Though it certainly depends on others what exactly they prioritize. I estimate that by the time we get around to MuSig, we may very well already have some kind of `SIGHASH_NOINPUT` or other more complicated scheme (I hope, maybe?) and might want to switch directly to Decker-Russell-Osuntokun instead of MuSig(2/DN)-Poon-Dryja. Regards, ZmnSCPxj ___ Lightning-dev mailing list Lightning-dev@lists.linuxfoundation.org https://lists.linuxfoundation.org/mailman/listinfo/lightning-dev
Re: [Lightning-dev] Deriving channel keys deterministically from seed, musig, and channel establishment v2
Good morning ZmnSCPxj, > > Solutions: > > > > 1. Naively, we could just derive a static key to be used as > > payment_basepoint, reused between all our channels, and watch the > > single resulting p2wsh script on-chain. > > Clearly this has terrible privacy implications. > > If the only problem is horrible privacy, and you have an > `OP_RETURN`identifying the channel counterparty node id anyway, would it not > be possible to tweak this for each channel? > static_payment_basepoint_key + hash(seed | counterparty_node_id) > This (should) result in a unique key for each counterparty, yet each > individual counterparty cannot predict this tweak (and break your privacy by > deriving the `static_payment_basepoint_key * G`). The OP_RETURN containing the encrypted counterparty node id is only an option, ideally it should not be required. Also, your proposal needs a counter too, to avoid reuse between multiple channels with the same counterparty. This counter is actually quite problematic as users should be able to open new channels after restoring from seed, which means they need to be able to figure out the last value of the counter reliably, which seems potentially problematic, so actually this might have to be a random nonce that is wide enough to make collisions unlikely... (potentially taking up valuable blockchain space in the OP_RETURN) Regards, SomberNight ___ Lightning-dev mailing list Lightning-dev@lists.linuxfoundation.org https://lists.linuxfoundation.org/mailman/listinfo/lightning-dev
Re: [Lightning-dev] Deriving channel keys deterministically from seed, musig, and channel establishment v2
Good morning SomberNight, > Solutions: > > 1. Naively, we could just derive a static key to be used as > payment_basepoint, reused between all our channels, and watch the > single resulting p2wsh script on-chain. > Clearly this has terrible privacy implications. If the only problem is horrible privacy, and you have an `OP_RETURN` identifying the channel counterparty node id anyway, would it not be possible to tweak this for each channel? static_payment_basepoint_key + hash(seed | counterparty_node_id) This (should) result in a unique key for each counterparty, yet each individual counterparty cannot predict this tweak (and break your privacy by deriving the `static_payment_basepoint_key * G`). ? Regards, ZmnSCPxj ___ Lightning-dev mailing list Lightning-dev@lists.linuxfoundation.org https://lists.linuxfoundation.org/mailman/listinfo/lightning-dev
[Lightning-dev] Deriving channel keys deterministically from seed, musig, and channel establishment v2
Hi all, TL;DR: an approach is described how to derive channel keys deterministically that allows certain forms of recovery from just a seed, that works today. This approach however will no longer work with e.g. MuSig key aggregation in the future. An idea for a proposal is given how the channel-open flow (e.g. as part of channel v2) could be changed to make a similar approach work independent of key aggregation. - While implementing anchor output support in Electrum, we have realised one difficulty is to do with the remote-force-close case where the to_remote output is no longer a simple p2wpkh. Currently, pre-anchor-support, Electrum sets option_static_remotekey to required (feature bit 12), and we restrict lightning usage to wallets that derive p2wpkh addresses, and payment_basepoint is set to a bip32-derived pubkey that corresponds to a wallet address. Hence, if a user were to restore from seed words, and their channel counterparty force closed their channel, the to_remote output of the broadcast commitment tx would directly pay to the user's wallet. That is, in many typical scenarios, funds are not lost when restoring from seed. (Also, if we are the channel-funder/opener, it is easy to find the funding transaction, just by testing txs in the wallet history. Further, for the cases we are the channel-funder/opener, there is a setting to put an OP_RETURN in the funding tx, which stores the nodeid of the counterparty, allowing us to identify who to contact to get the channel closed. Also, we are (ab)using dataloss_protect to ask the remote to force-close when restoring from seed, so the user does not even have to wait for an arbitrarily long time.) With anchors, the to_remote is now a p2wsh that involves a CSV, and we cannot easily make this script correspond to a wallet address, i.e. we lose the property that the remote-force-close pays directly to a wallet address. So, the problem we would like to solve, is: - having seed words - having access to blockchain data - somehow having identified our channel counterparties (node IDs), and our channels with them (funding outpoints) - and assuming we can get the remote to do a force-close --> we would like to be able to spend the to_remote output Solutions: 1) Naively, we could just derive a static key to be used as payment_basepoint, reused between all our channels, and watch the single resulting p2wsh script on-chain. Clearly this has terrible privacy implications. 2) Or, we could derive a new bip32 chain/sequence of pubkeys used as payment_basepoint for channels, and watch these p2wsh scripts, with a gap limit. Particularly the gap limit part makes this undesirable though (just consider having more than "gap limit" channels open and restoring from seed). Instead, it seems desirable to see whether we can extract some entropy from the blockchain, and use that as a nonce to be combined with a static private secret derived from our seed. We could extract data either from the funding tx, or from the remote-commitment-transaction that spent the funding output. 3) We exploit the fact that the funding output uses a 2of2 OP_CHECKMULTISIG script composed of the funding pubkeys of each party. The funding pubkey itself can be used as a nonce, and it can be recovered from the witness of the commitment tx. The privkey for payment_basepoint can then be derived as e.g. hash(bip32_derive(seed, HARDCODED_PATH) + funding_pubkey). In fact (3) is not novel at all: eclair has been deriving all their channel keys like this [0] for some time, from a static seed-based secret combined with the funding_pubkey as nonce, and generating the funding_privkey from ~os.urandom. Electrum will likely use (3) at least for the payment_basepoint, as part of adapting to anchors. - Note that the idea (3) relies on recovering the funding_pubkey from the witness of the spending transaction, which will break in the future if the funding script is changed to e.g. a p2tr that uses musig. Crucially, note that all the approach needs is some blockchain-visible nonce that is already known at the time we need to construct the open_channel message (as we want to be able to derive some of the keys that are sent as part of the open_channel message (e.g. payment_basepoint) from it). As long as the funding output uses a 2of2 OP_CHECKMULTISIG, the local funding_pubkey fits the bill. Note that irrespective of any restrictions on the script used in the funding output, we could use the funding scriptPubKey/address as the nonce, if the open_channel/accept_channel messages were split into two. For example, instead of the single round of open_channel/accept_channel, there could be two rounds: - an open_channel_part1, where the peers exchange only the funding_pubkey (and the other non-pubkey fields), and - an open_channel_part2, where the rest of the pubkeys are sent This way the peers would learn what the funding address would be after the first round finishes, and could potentially use that