From thomasv at electrum.org Mon Aug 14 12:59:16 2023 From: thomasv at electrum.org (Thomas Voegtlin) Date: Mon, 14 Aug 2023 14:59:16 +0200 Subject: [Lightning-dev] Resumable channels using OP_CHECKSIGFROMSTACK Message-ID: <0f84f9be-b68e-47db-46b6-3230e4509811@electrum.org> Hello list, Here is an idea to make lightning channels resumable from wallet seed. I have not implemented it yet, and there might be issues I am not seeing. Thus, I would be grateful for feedback. Thanks to SomberNight and Peter Todd for reviewing earlier versions of this proposal. Thomas ----------------------------------------------- Resumable channels using OP_CHECKSIGFROMSTACK ============================================= In order to resume the activity of a Lightning channel, one needs a backup that contains all the information about the current channel state. The need to perform channel backups has plagued user experience, with many implementations reverting to static backups, which can be used to recover funds, but not to resume channel operations. Asking your channel counterparty to store your channel state has the advantage to make backup operations atomic. However, there is no guarantee that this is safe. Indeed, if the other party suspects that you have lost your state (for example, because you have been offline for a long time, or if they can see that you requested blockchain information following a certain pattern), they can try to send you a revoked state, and there is no way to punish them for doing that. Here is a proposal for a new type of channel funding transaction, where the redeem script has an additional spending path, that accepts a fraud proof: a proof that the channel counterparty has lied about the current state. This proposal requires two opcodes that are currently not available in Bitcoin: OP_CAT and OP_CHECKSIGFROMSTACK. Roles are asymmetric in this channel: Alice is a client, and Bob is a server, who stores Alice's state. Thus, this proposal is mostly suited for private channels with Lightning service providers. During channel reestablishment, Bob will send her latest state to Alice, using an extra field in the channel_reestablish message. Since Alice cannot punish Bob if she has lost her state, she must not let Bob learn whether she still has her state. Thus, Alice will never send channel_reestablish first. This proposal assumes that Alice and Bob each have a clock, and that these clocks do not drift too much relative to each other. The channel may become unusable if clocks differ too much, as discussed below. Simplified description ---------------------- The *state* of the channel refers to everything Alice needs in order to resume channel operations. With every new commitment, Alice sends her current state, with her signature of that state: - if Alice sends commitment_signed, the state and signature are included in that message. - if Alice receives commitment_signed, the state and signature will be included in the next revoke_and_ack sent by Alice. With every new commitment, Bob sends a signed tuple (ctn, timestamp), where ctn is the current commitment number (for the moment, forget about the distinction between local and remote ctns), and timestamp is the current time for Bob. - if Bob sends commitment_signed, the signed tuple is included in that message. - if Bob receives commitment_signed, the signed tuple will be included in the next revoke_and_ack sent by Bob. The private key used by Bob to sign the tuples is constant over the lifetime of the channel, and it must not be reused in other channels. The corresponding public key will be used in the fraud proof spending path of the redeem script. Alice verifies Bob's signature. She also checks that the received timestamps are reasonable (see below) and strictly monotonic. With every channel_reestablish message, Bob will send two extra fields: - (ctn, timestamp, bob_signature) - (alice_state, alice_signature). Alice verifies that the state she received was signed by her, and that the (ctn, timestamp) tuple was signed by Bob. She also checks that the timestamp is reasonable. Fraud Proofs ------------ Let us assume that Bob tries to send a revoked state to Alice in channel_reestablish. The channel_reestablish received by Alice contains a signed tuple (ctn1, t1), with t1 current timestamp. However, another signed tuple (ctn2, t2) has been received in the past, with ctn1 < ctn2 and t1 > t2. If Alice has not lost her state, she will now hold two signed tuples (ctn1, t1) and (ctn2, t2), that satisfy ctn1 < ctn2 and t1 > t2. This constitutes a fraud proof. With OP_CAT and OP_CHECKSIGFROMSTACK, we can build a script that verifies the fraud proof, and allows Alice to unilaterally spend the channel funding output. Here is an example of such a script: witness: [ alice_signature(transaction) bob_signature((ctn1,timestamp1)) ctn1 timestamp1 bob_signature((ctn2,timestamp2)) ctn2 timestamp2 ] witness_script: OP_PICK 1 OP_PICK 4 OP_LESSTHAN # verify ctn1 < ctn2 OP_VERIFY OP_PICK 0 OP_PICK 3 OP_GREATERTHANOREQUAL # verify timestamp1 >= timestamp2 OP_VERIFY # check signatures OP_CAT OP_PUSHDATA bob_pubkey # we may use Bob's funding_pubkey OP_CHECKSIGFROMSTACK OP_VERIFY OP_CAT OP_PUSHDATA bob_pubkey OP_CHECKSIGFROMSTACK OP_VERIFY OP_PUSHDATA alice_pubkey # we may use Alice's funding_pubkey OP_CHECKSIGVERIFY In order to keep things simple, a few details have been omitted in the description: - Bob actually needs to send both the local and the remote ctns in his signed tuples. A pair of tuples is a fraud proof if the order is violated for either local or remote ctns. Thus, the actual script will be more complex than what has been drafted above. - Integers pushed on the Bitcoin stack are maximum 4 bytes (31 bits + 1 bit for the sign). Since commitment numbers are 48 bits long, they will need to be split into two integers. Timestamps might require a similar decomposition. This adds further complexity to the redeem script. - Note that Bob must strictly increase his timestamp on each ctn. This puts a lower bound on the precision used for timestamps. Reasonable Timestamps --------------------- Since Alice and Bob do not have the same clock, Bob may legitimately send a timestamp that is in Alice's past or future. Every time Alice receives a timestamp from Bob, she compares it to her current time. - If Alice receives a timestamp that is in her future, instead of closing the channel, she may wait it out before she accepts to resume operations. - If Alice receives a timestamp that is too far in her past, she should disconnect. Indeed, Bob may be sending an old state and replaying old timestamps, which is not punishable. In that case, Alice should not automatically force close the channel, because she can only do that if she has not lost her state; if force-closing was automatic, not force-closing would reveal to Bob that she has lost her state. A delay needs to be tolerated by Alice, because Bob does not have the same clock; that delay should be chosen so that it is always smaller than the interval between two sessions. Saving Bandwidth ---------------- Alice's channel state does not need to be sent with every commitment, if it is made of information that is known by both parties. In that case, it is sufficient for Alice to send her signature of the current state. Both Alice and Bob must be able to serialize the state, so that Alice can verify her own signature against a serialization of the state created by Bob. The state only needs to be sent by Bob once, in channel_reestablish. For this to work, the channel state cannot include information that is private to Alice. If the private keys used by Alice in the channel are derived deterministically from her wallet seed, they do not need to be part of the state. Alternatively, private keys may be included in an encrypted blob that is included in the state. Since that encrypted blob is constant, it only needs to be sent once by Alice, during the channel opening negotiation. Bob will save it and add it to the state sent in channel_reestablish. In addition, the state must not include any payment_hash preimage known by Alice; thus, Alice will have to fail incoming payments for those preimages, if she has lost her state. The channel state should include the compact storage of per-commitment secrets sent by Bob. Concluding remarks ------------------ - Obviously, this proposal assumes that Alice remembers with whom she has an open channel. - Alice may restore her wallet from seed on a new device, while the initial wallet is still active. In that case, Alice must stop using the channels on her old device. Thus, Alice should disconnect if she has not lost her state and receives a state with a ctn that is in her future. This ensures that only one device uses the channels. - Without waiting for OP_CHECKSIGFROMSTACK to be available in Bitcoin, it would be possible for Bob to lockup funds on another blockchain such as Liquid. It is also possible to create fraud proofs that are not used in a redeem script, but that are tied to Bob's public identity and reputation. In that case, Bob should sign with his node pubkey, and fraud proofs will need to include a short channel id.