Delegated signatures in Bitcoin within existing rules, no fork required

Delegated signatures in Bitcoin within existing rules, no fork required
2021-03-16  6:09 ` ZmnSCPxj
  
From: Jeremy @ 2021-03-10 23:55 UTC (permalink / raw)
  To: Bitcoin development mailing list

[-- Attachment #1: Type: text/plain, Size: 4736 bytes --]

I'm aware that some folks (I think nullc, sipa, myself... maybe more?) are
aware of how to do script delegation in Bitcoin today (without any
modifications to Bitcoin), but realized in a conversation with Andrew P
that the technique is not widely known. So I figured it made sense to do a
brief explainer of how this works for the archives / so the technique is
documented. If someone has other citations for this, please respond below.

If you like cartoons follow along here:

https://docs.google.com/presentation/d/1ikcthy3p-Ah59pJyss0TLEj-Q2FF6tv7BXhkORzErAE/edit#slide=id.p

Technically what we are doing is delegating a UTXO to a specific UTXO, and
not to a script.


Suppose you have a coin on UTXO A. You would like to delegate it to script
S. You can either scan the chain for any UTXOs bound to S or use some
arbitrary coin B to create a transaction X with an output D that has script
S (doesn't have to have any value, but let's say it has a nominal amount to
avoid dust issues). Because tx X is not malleable, we don't need to
actually broadcast it and spend B till we want to use the delegation, and
it can be created (for the TXID) without B's owner being online. However
you get the UTXO, and if it exists or not yet, let's call it D.

*Note: if you're using a delegation script multiple times, you can optimize
the creation step a bit*

Now, using A, you sign a transaction with 2 inputs (one of them being D)
and SIGHASH_NONE. This signs all of the inputs (but not their sequences!)
but none of the outputs. Let's call this transaction stub G.

Now, using S, you sign D's input on G with SIGHASH_ALL and the outputs you
want to create (whatever they may be). Let's call the finished transaction
F.

Effectively, the holder of A has delegated the control of their coin to a
specific instance of the script S. Once delegated, S may authorize almost
any transaction they want (complicated if they want to sign a multiple
input transaction; but there are good substitutes).

Advanced Topics:

*Revocation*: There are multiple ways to revoke, either moving A, moving D,
refusing to sign and create D (when D is derived from B), etc. Because
these are UTXO-bound they are revocable. (the cartoon may help here)
*Cross input delegation*: A set of N coins may create a sighash_none
transaction with 1 additional input for the delegating script
*Partial Spending Authorizations*: Replacing sighash_none with
sighash_single allows an input to specify a single change address (plug --
OP_CTV covenants can be thought of as a way to get around sighash_single to
allow sighash_single to cover signing a set of outputs)
*Delegation after time*: Because the lock_time field is covered,
delegations can be set up to only be valid at some point in the future.
Only a single sequence lock per delegated coin may be used directly.
*Multiple Delegates: *By signing a txn with several delegate outputs, it is
possible to enforce multiple disparate conditions. Normally this is
superfluous -- why not just concatenate S1 and S2? The answer is that you
may have S1 require a relative height lock and S2 require a relative time
lock (this was one of the mechanisms investigated for powswap.com).
*Sequenced Contingent Delegation*: By constructing a specific TXID that may
delegate the coins, you can make a coin's delegation contingent on some
other contract reaching a specific state. For example, suppose I had a
contract that had 100 different possible end states, all with fixed
outpoints at the end. I could delegate coins in different arrangements to
be claimable only if the contract reaches that state. Note that such a
model requires some level of coordination between the main and observing
contract as each Coin delegate can only be claimed one time.
*CTV Specific P2SH Non Coin Delegation: *OP_CTV allows for a similar form
of delegation where by a Segwit P2SH address, as a part of the CTV
committed data, can be used without binding it to any specific UTXO. With
the addition of OP_CAT, it would be possible to both programmatically
change the outputs (rather than just approving the fixed txn) and to
dynamically select the script.
*Redelegating: *This is where A delegates to S, S delegates to S'. This
type of mechanism most likely requires the coin to be moved on-chain to the
script (A OR S or S'), but the on-chain movement may be delayed (via
presigned transactions) until S' actually wants to do something with the
coin.

There are obviously many other things you can do with delegation in
general, the above are specific to how coin delegation is done. I'm
probably missing some of the fun stuff -- please riff on this!

Best,

Jeremy

--
@JeremyRubin <https://twitter.com/JeremyRubin>
<https://twitter.com/JeremyRubin>

[-- Attachment #2: Type: text/html, Size: 9178 bytes --]

 permalink raw reply	[|nested]
2021-03-10 23:55 [bitcoin-dev] Delegated signatures in Bitcoin within existing rules, no fork required Jeremy

  2021-03-16  6:16   ` Jeremy
  
From: ZmnSCPxj @ 2021-03-16  6:09 UTC (permalink / raw)
  To: Jeremy, Bitcoin Protocol Discussion

Good morning Jeremy,

This is a very cool idea!

> Multiple Delegates: By signing a txn with several delegate outputs, it is possible to enforce multiple disparate conditions. Normally this is superfluous -- why not just concatenate S1 and S2? The answer is that you may have S1 require a relative height lock and S2 require a relative time lock (this was one of the mechanisms investigated for powswap.com).

I am somewhat confused by this.
Do you mean that the delegating transaction (the one signed using the script of A with `SIGHASH_NONE`) has as input (consumes) multiple delegate outputs D1, D2... with individual scripts S1, S2... ?

> Sequenced Contingent Delegation: By constructing a specific TXID that may delegate the coins, you can make a coin's delegation contingent on some other contract reaching a specific state. For example, suppose I had a contract that had 100 different possible end states, all with fixed outpoints at the end. I could delegate coins in different arrangements to be claimable only if the contract reaches that state. Note that such a model requires some level of coordination between the main and observing contract as each Coin delegate can only be claimed one time.

Does this require that each contract end-state have a known TXID at setup time?

> Redelegating: This is where A delegates to S, S delegates to S'. This type of mechanism most likely requires the coin to be moved on-chain to the script (A OR S or S'), but the on-chain movement may be delayed (via presigned transactions) until S' actually wants to do something with the coin.

The script `A || S || S'` suggests that delegation effectively still allows the original owner to still control the coin, right?
Which I suppose is implied by "Revocation" above.

Regards,
ZmnSCPxj



 permalink raw reply	[|nested]
2021-03-16  6:09 ` ZmnSCPxj

  2021-03-16  8:36     ` ZmnSCPxj
  
From: Jeremy @ 2021-03-16  6:16 UTC (permalink / raw)
  To: ZmnSCPxj;  Bitcoin Protocol Discussion

[-- Attachment #1: Type: text/plain, Size: 2535 bytes --]

inline responses
--
@JeremyRubin <https://twitter.com/JeremyRubin>
<https://twitter.com/JeremyRubin>


On Mon, Mar 15, 2021 at 11:10 PM ZmnSCPxj <ZmnSCPxj@protonmail•com> wrote:

> Good morning Jeremy,
>
> This is a very cool idea!
>
> > Multiple Delegates: By signing a txn with several delegate outputs, it
> is possible to enforce multiple disparate conditions. Normally this is
> superfluous -- why not just concatenate S1 and S2? The answer is that you
> may have S1 require a relative height lock and S2 require a relative time
> lock (this was one of the mechanisms investigated for powswap.com).
>
> I am somewhat confused by this.
> Do you mean that the delegating transaction (the one signed using the
> script of A with `SIGHASH_NONE`) has as input (consumes) multiple delegate
> outputs D1, D2... with individual scripts S1, S2... ?
>
>
Correct -- you can do this if you want multiple independent delegates to be
able to revoke, or if you want S1 and S2 to mix height + time based
relative locks -- bonus points if D1.txid == D2.txid, then you can be sure
they're counting from the same origin point.



> > Sequenced Contingent Delegation: By constructing a specific TXID that
> may delegate the coins, you can make a coin's delegation contingent on some
> other contract reaching a specific state. For example, suppose I had a
> contract that had 100 different possible end states, all with fixed
> outpoints at the end. I could delegate coins in different arrangements to
> be claimable only if the contract reaches that state. Note that such a
> model requires some level of coordination between the main and observing
> contract as each Coin delegate can only be claimed one time.
>
> Does this require that each contract end-state have a known TXID at setup
> time?
>

Without anyprevout or similar, I believe so.



>
> > Redelegating: This is where A delegates to S, S delegates to S'. This
> type of mechanism most likely requires the coin to be moved on-chain to the
> script (A OR S or S'), but the on-chain movement may be delayed (via
> presigned transactions) until S' actually wants to do something with the
> coin.
>
> The script `A || S || S'` suggests that delegation effectively still
> allows the original owner to still control the coin, right?
> Which I suppose is implied by "Revocation" above.
>

Yes, redelegating (or I guess rather recursive delegation?) would mean A,
S, and S' are all in play. if you want to revoke just A, then S must move
to a utxo with S and S'.

>
> Regards,
> ZmnSCPxj
>
>

[-- Attachment #2: Type: text/html, Size: 4226 bytes --]

 permalink raw reply	[|nested]
2021-03-16  6:16   ` Jeremy

  2021-03-17  6:30       ` Jeremy
  
From: ZmnSCPxj @ 2021-03-16  8:36 UTC (permalink / raw)
  To: Jeremy;  Bitcoin Protocol Discussion

Good morning Jeremy,

Thank you.

Assuming only keys, an easier way of delegating would be simply to give a copy of the privkey outright to the delegatee.

However, an advantage of this technique you described is that the delegator can impose additional restrictions that are programmable via any SCRIPT, an ability that merely handing over the privkey cannot do.
Thus the technique has an ability that mere handover cannot achieve.

If the delegatee is a known single entity, and S is simply the delegatee key plus some additional restrictions, it may be possible to sign with `SIGHASH_ALL` a transaction that spends A and D, and outputs to a singlesig of the delegatee key.
This would avoid the use of `SIGHASH_NONE`, for a mild improvement in privacy.
The output would still allow the delegatee to dispose of the funds by its unilateral decision subject to the fulfillment of the script S (at the cost of yet another transaction).
On the other hand, if S is unusual enough, the enhanced privacy may be moot (the S already marks the transaction as unusual), so this variation has little value.

In terms of offchain technology, if the delegator remains online, the delegatee may present a witness satisfying S to the delegator, and ask the delegator to provide an alternate transaction that spends A directly without spending D and outputs to whatever the delegatee wants.
The delegator cannot refuse since the delegatee can always use the `SIGHASH_NONE` signature and spend to whatever it decides provided it can present a witness satisfying S.
This is basically a typical "close transaction" for layer 2 technology.
On the other hand, one generalized use-case for delegation would be if the delegator suspects it may not be online or able to sign with the delegator key, so this variation has reduced value as well.

Regards,
ZmnSCPxj


 permalink raw reply	[|nested]
2021-03-16  8:36     ` ZmnSCPxj

  2021-03-24 13:33         ` Guido Dassori
  
From: Jeremy @ 2021-03-17  6:30 UTC (permalink / raw)
  To: ZmnSCPxj;  Bitcoin Protocol Discussion

[-- Attachment #1: Type: text/plain, Size: 4523 bytes --]

ZmnSCPxj,

The chief reason to use SIGHASH_NONE (or SIGHASH_SINGLE for partial funds
delegations) is to make it so that the delegator can dynamically choose
things like a change output. Otherwise you need to know exactly what you
want beforehand.

I'd note that you can also achieve a decent amount of scripting capability
for fully pre-signed transactions using layered encryption. E.g., given
script Checksig(Alice) and Checksig(Bob), you can delegate to
2 of CheckMulti(Carol, Dave, Eve) by (for example) encrypting either a
presigned txn or the actual sk's themselves with enc(Carol, enc(Dave, m)),
enc(Carol, enc(Eve, m)), enc(Dave, enc(Eve, m)). This allows you to
post-hoc delegate a presigned (or the keys -- which may or may not be safe
if they are from a HD wallet mind you). You can also do a variant of
timelock encryption by encrypting m using a verifiable delay function (this
actually permits a new kind of relative lock, depending on where you layer
the VDF enc, which would be N seconds from when the two parties agree to
decrypt). The general protocol can also be optimized by giving Carol
enc(Dave, m) and enc(Eve) but then you have to have a confidential channel
to each delegate. You can also do a ZKCP type thing if you prove that a txn
matching a specific format is encrypted with the preimage to a hash.
There's a lot you can do as improvement on simple "hand the key" -- this
sounds kinda similar to scriptless scripts?

W.r.t. privacy, it certainly is a hit. But I think in situations where
privacy is a goal, then the delegation can contact the original signer and
ask to cooperate. However in some circumstances that won't be viable given
access to keys or whatnot. I would suggest in these cases that you can do a
hybrid: delegate to a script and provide a default sighash_all txn, and a
modifiable sighash_none/single. Then the delegates can decide what is best
to use and optimistically get the originals to sign off.

Interestingly, there is a subset of cases where it is desirable to have
privacy *from the original script holder*. Conceivably the tx does need to
be public at some point, but for interest, once delegated to from S to S',
S' could show a signature covering a txn hash from S', and request that S
sign it. S' can reveal partial information -- e.g., which inputs are being
spent, but not which outputs are being created. Maybe not super useful, but
it is interesting to note of course.

Best,

Jeremy
--
@JeremyRubin <https://twitter.com/JeremyRubin>
<https://twitter.com/JeremyRubin>


On Tue, Mar 16, 2021 at 1:36 AM ZmnSCPxj <ZmnSCPxj@protonmail•com> wrote:

> Good morning Jeremy,
>
> Thank you.
>
> Assuming only keys, an easier way of delegating would be simply to give a
> copy of the privkey outright to the delegatee.
>
> However, an advantage of this technique you described is that the
> delegator can impose additional restrictions that are programmable via any
> SCRIPT, an ability that merely handing over the privkey cannot do.
> Thus the technique has an ability that mere handover cannot achieve.
>
> If the delegatee is a known single entity, and S is simply the delegatee
> key plus some additional restrictions, it may be possible to sign with
> `SIGHASH_ALL` a transaction that spends A and D, and outputs to a singlesig
> of the delegatee key.
> This would avoid the use of `SIGHASH_NONE`, for a mild improvement in
> privacy.
> The output would still allow the delegatee to dispose of the funds by its
> unilateral decision subject to the fulfillment of the script S (at the cost
> of yet another transaction).
> On the other hand, if S is unusual enough, the enhanced privacy may be
> moot (the S already marks the transaction as unusual), so this variation
> has little value.
>
> In terms of offchain technology, if the delegator remains online, the
> delegatee may present a witness satisfying S to the delegator, and ask the
> delegator to provide an alternate transaction that spends A directly
> without spending D and outputs to whatever the delegatee wants.
> The delegator cannot refuse since the delegatee can always use the
> `SIGHASH_NONE` signature and spend to whatever it decides provided it can
> present a witness satisfying S.
> This is basically a typical "close transaction" for layer 2 technology.
> On the other hand, one generalized use-case for delegation would be if the
> delegator suspects it may not be online or able to sign with the delegator
> key, so this variation has reduced value as well.
>
> Regards,
> ZmnSCPxj
>

[-- Attachment #2: Type: text/html, Size: 6665 bytes --]

 permalink raw reply	[|nested]
2021-03-17  6:30       ` Jeremy

  
From: Guido Dassori @ 2021-03-24 13:33 UTC (permalink / raw)
  To: Jeremy, Bitcoin Protocol Discussion

[-- Attachment #1: Type: text/plain, Size: 5333 bytes --]

Hello Jeremy,

I find this a very interesting idea :-)
Actually I implemented something similar a bit ago in a POC, available on
GH since a while: https://github.com/gdassori/btc-bargain

At this very moment we're working to make it production ready and cut our
transaction fees (we run a 2-on-3 wallet with buy\sell features) down to
~5%.

Guido
https://twitter.com/khs9ne

Il giorno mer 17 mar 2021 alle ore 07:30 Jeremy via bitcoin-dev <
bitcoin-dev@lists•linuxfoundation.org> ha scritto:

> ZmnSCPxj,
>
> The chief reason to use SIGHASH_NONE (or SIGHASH_SINGLE for partial funds
> delegations) is to make it so that the delegator can dynamically choose
> things like a change output. Otherwise you need to know exactly what you
> want beforehand.
>
> I'd note that you can also achieve a decent amount of scripting capability
> for fully pre-signed transactions using layered encryption. E.g., given
> script Checksig(Alice) and Checksig(Bob), you can delegate to
> 2 of CheckMulti(Carol, Dave, Eve) by (for example) encrypting either a
> presigned txn or the actual sk's themselves with enc(Carol, enc(Dave, m)),
> enc(Carol, enc(Eve, m)), enc(Dave, enc(Eve, m)). This allows you to
> post-hoc delegate a presigned (or the keys -- which may or may not be safe
> if they are from a HD wallet mind you). You can also do a variant of
> timelock encryption by encrypting m using a verifiable delay function (this
> actually permits a new kind of relative lock, depending on where you layer
> the VDF enc, which would be N seconds from when the two parties agree to
> decrypt). The general protocol can also be optimized by giving Carol
> enc(Dave, m) and enc(Eve) but then you have to have a confidential channel
> to each delegate. You can also do a ZKCP type thing if you prove that a txn
> matching a specific format is encrypted with the preimage to a hash.
> There's a lot you can do as improvement on simple "hand the key" -- this
> sounds kinda similar to scriptless scripts?
>
> W.r.t. privacy, it certainly is a hit. But I think in situations where
> privacy is a goal, then the delegation can contact the original signer and
> ask to cooperate. However in some circumstances that won't be viable given
> access to keys or whatnot. I would suggest in these cases that you can do a
> hybrid: delegate to a script and provide a default sighash_all txn, and a
> modifiable sighash_none/single. Then the delegates can decide what is best
> to use and optimistically get the originals to sign off.
>
> Interestingly, there is a subset of cases where it is desirable to have
> privacy *from the original script holder*. Conceivably the tx does need to
> be public at some point, but for interest, once delegated to from S to S',
> S' could show a signature covering a txn hash from S', and request that S
> sign it. S' can reveal partial information -- e.g., which inputs are being
> spent, but not which outputs are being created. Maybe not super useful, but
> it is interesting to note of course.
>
> Best,
>
> Jeremy
> --
> @JeremyRubin <https://twitter.com/JeremyRubin>
> <https://twitter.com/JeremyRubin>
>
>
> On Tue, Mar 16, 2021 at 1:36 AM ZmnSCPxj <ZmnSCPxj@protonmail•com> wrote:
>
>> Good morning Jeremy,
>>
>> Thank you.
>>
>> Assuming only keys, an easier way of delegating would be simply to give a
>> copy of the privkey outright to the delegatee.
>>
>> However, an advantage of this technique you described is that the
>> delegator can impose additional restrictions that are programmable via any
>> SCRIPT, an ability that merely handing over the privkey cannot do.
>> Thus the technique has an ability that mere handover cannot achieve.
>>
>> If the delegatee is a known single entity, and S is simply the delegatee
>> key plus some additional restrictions, it may be possible to sign with
>> `SIGHASH_ALL` a transaction that spends A and D, and outputs to a singlesig
>> of the delegatee key.
>> This would avoid the use of `SIGHASH_NONE`, for a mild improvement in
>> privacy.
>> The output would still allow the delegatee to dispose of the funds by its
>> unilateral decision subject to the fulfillment of the script S (at the cost
>> of yet another transaction).
>> On the other hand, if S is unusual enough, the enhanced privacy may be
>> moot (the S already marks the transaction as unusual), so this variation
>> has little value.
>>
>> In terms of offchain technology, if the delegator remains online, the
>> delegatee may present a witness satisfying S to the delegator, and ask the
>> delegator to provide an alternate transaction that spends A directly
>> without spending D and outputs to whatever the delegatee wants.
>> The delegator cannot refuse since the delegatee can always use the
>> `SIGHASH_NONE` signature and spend to whatever it decides provided it can
>> present a witness satisfying S.
>> This is basically a typical "close transaction" for layer 2 technology.
>> On the other hand, one generalized use-case for delegation would be if
>> the delegator suspects it may not be online or able to sign with the
>> delegator key, so this variation has reduced value as well.
>>
>> Regards,
>> ZmnSCPxj
>>
> _______________________________________________
> bitcoin-dev mailing list
> bitcoin-dev@lists•linuxfoundation.org
> https://lists.linuxfoundation.org/mailman/listinfo/bitcoin-dev
>

[-- Attachment #2: Type: text/html, Size: 8029 bytes --]

 permalink raw reply	[|nested]