Pay to signature hash as a covenant

Pay to signature hash as a covenant
2022-05-03  9:35 ` ZmnSCPxj
  2022-05-21 21:24 ` AdamISZ
  
From: vjudeu @ 2022-05-03  7:37 UTC (permalink / raw)
  To: bitcoin-dev

Typical P2PK looks like that: "<signature> <pubkey> OP_CHECKSIG". In a typical scenario, we have "<signature>" in out input and "<pubkey> OP_CHECKSIG" in our output. I wonder if it is possible to use covenants right here and right now, with no consensus changes, just by requiring a specific signature. To start with, I am trying to play with P2PK and legacy signatures, but it may turn out, that doing such things with Schnorr signatures will be more flexible and will allow more use cases.

The simplest "pay to signature" script I can think of is: "<signature> OP_SWAP OP_CHECKSIG". Then, any user can provide just a "<pubkey>" in some input, as a part of a public key recovery. The problem with such scheme is that it is insecure. Another problem is that we should handle it carefully, because signatures are removed from outputs. However, we could replace it with some signature hash, then it will be untouched, for example: "OP_TOALTSTACK OP_DUP OP_HASH160 <signatureHash> OP_EQUALVERIFY OP_FROMALTSTACK OP_CHECKSIG".

And then, signatures are more flexible than public keys, because we can use many different sighashes to decide, what kind of transaction is allowed and what should be rejected. Then, if we could use the right signature with correct sighashes, it could be possible to disable key recovery and require some specific public key, then that scheme could be safely used again. I still have no idea, how to complete that puzzle, but it seems to be possible to use that trick, to restrict destination address. Maybe I should wrap such things in some kind of multisig or somehow combine it with OP_CHECKSIGADD, any ideas?



 permalink raw reply	[|nested]
2022-05-03  7:37 [bitcoin-dev] Pay to signature hash as a covenant vjudeu

  2022-05-21 21:24 ` AdamISZ
  
From: ZmnSCPxj @ 2022-05-03  9:35 UTC (permalink / raw)
  To: vjudeu, Bitcoin Protocol Discussion

Good morning vjudeu,

> Typical P2PK looks like that: "<signature> <pubkey> OP_CHECKSIG". In a typical scenario, we have "<signature>" in out input and "<pubkey> OP_CHECKSIG" in our output. I wonder if it is possible to use covenants right here and right now, with no consensus changes, just by requiring a specific signature. To start with, I am trying to play with P2PK and legacy signatures, but it may turn out, that doing such things with Schnorr signatures will be more flexible and will allow more use cases.
>
>
> The simplest "pay to signature" script I can think of is: "<signature> OP_SWAP OP_CHECKSIG". Then, any user can provide just a "<pubkey>" in some input, as a part of a public key recovery. The problem with such scheme is that it is insecure. Another problem is that we should handle it carefully, because signatures are removed from outputs. However, we could replace it with some signature hash, then it will be untouched, for example: "OP_TOALTSTACK OP_DUP OP_HASH160 <signatureHash> OP_EQUALVERIFY OP_FROMALTSTACK OP_CHECKSIG".
>
> And then, signatures are more flexible than public keys, because we can use many different sighashes to decide, what kind of transaction is allowed and what should be rejected. Then, if we could use the right signature with correct sighashes, it could be possible to disable key recovery and require some specific public key, then that scheme could be safely used again. I still have no idea, how to complete that puzzle, but it seems to be possible to use that trick, to restrict destination address. Maybe I should wrap such things in some kind of multisig or somehow combine it with OP_CHECKSIGADD, any ideas?

You can do the same thing with P2SH, P2WSH, and P2TR (in a Tapscript) as well.

Note that it is generally known that you *can* use pre-signed transactions to implement vaults.
Usually what we refer to by "covenant" is something like "this output will definitely be constructed here" without necessarily requiring a signature.

HOWEVER, what you are proposing is not ***quite*** pre-signed transactions!
Instead, you are (ab)using signatures in order to commit to particular sighashes.

First, let me point out that you do not need to hash the signature and *then* use a raw `scriptPubKey`, which I should *also* point it is not going to pass `IsStandard` checks (and will not propagate on the mainnet network reliably, only on testnet).
Instead, you can use P2WSH and *include* the signature outright in the `redeemScript`.
Since the output `scriptPubKey` is really just the hash of the `redeemScript`, this is automatically a hash of a signature (plus a bunch of other bytes).

So your proposal boils down to using P2WSH and having a `redeemScript`:

    redeemScript = <fixedSignature> <fixPubKey> OP_CHECKSIG

Why include the `fixPubKey` in the `redeemScript`?
In your scheme, you would provide the signature and pubkey in the `scriptSig` that spends the `scriptPubKey`.
But in a post-P2WSH world, `redeemScript` will also be provided in the `witness`, so you *also* provide both the signature and the pubkey, and both are hashed before appearing on the `scriptPubKey` --- which is exactly what you are proposing anyway.

The above pre-commits to a particular transaction, depending on the `SIGHASH` flags of the `fixedSignature`.
Of note is that the `fixPubKey` can have a throwaway privkey, or even a ***publicly-shared*** privkey.
Even if an alternate signature is created from  well-known privkey, the `redeemScript` will not allow any other signature to be accepted, it will only use the one that is hardcoded into the script.
Using a publicly-shared privkey would allow us to compute just the expected `sighash`. them derove the `fixedSignature` that should be in the `redeemScript`.

In particular, this scheme would work just as well for the "congestion control" application proposed for `OP_CTV`.
`OP_CTV` still wins in raw WUs spent (just the 32-WU hash), but in the absence of `OP_CTV` because raisins, this would also work (but you reveal a 33-WU pubkey, and a 73-WU/64-WU signature, which is much larger).
Validation speed is also better for `OP_CTV`, as it is just a hash, while this scheme uses signature validation in order to commit to a specific hash anyway (a waste of CPU time, since you could just check the hash directly instead of going through the rigmarole of a signature, but one which allows us to make non-recursive covenants with some similarities to `OP_CTV`).

A purported `OP_CHECKSIGHASHVERIFY` which accepts a `SIGHASH` flag and a hash, and checks that the sighash of the transaction (as modified by the flags) is equal to the hash, would be more efficient, and would also not differ by much from `OP_CTV`.

This can be used in a specific branch of an `OP_IF` to allow, say, a cold privkey to override this branch, to start a vault construction.

The same technique should work with Tapscripts inside Taproot (but the `fixedPubKey` CANNOT be the same as the internal Taproot key!).

Regards,
ZmnSCPxj


 permalink raw reply	[|nested]
2022-05-03  7:37 [bitcoin-dev] Pay to signature hash as a covenant vjudeu
  2022-05-03  9:35 ` ZmnSCPxj

  
From: AdamISZ @ 2022-05-21 21:24 UTC ( / )
  To: vjudeu, Bitcoin Protocol Discussion






Sent with ProtonMail secure email.
------- Original Message -------
On Tuesday, May 3rd, 2022 at 02:37, vjudeu via bitcoin-dev <bitcoin-dev@lists•linuxfoundation.org> wrote:


> Typical P2PK looks like that: "<signature> <pubkey> OP_CHECKSIG". In a typical scenario, we have "<signature>" in out input and "<pubkey> OP_CHECKSIG" in our output. I wonder if it is possible to use covenants right here and right now, with no consensus changes, just by requiring a specific signature. To start with, I am trying to play with P2PK and legacy signatures, but it may turn out, that doing such things with Schnorr signatures will be more flexible and will allow more use cases.
>
>
> The simplest "pay to signature" script I can think of is: "<signature> OP_SWAP OP_CHECKSIG". Then, any user can provide just a "<pubkey>" in some input, as a part of a public key recovery. The problem with such scheme is that it is insecure. Another problem is that we should handle it carefully, because signatures are removed from outputs. However, we could replace it with some signature hash, then it will be untouched, for example: "OP_TOALTSTACK OP_DUP OP_HASH160 <signatureHash> OP_EQUALVERIFY OP_FROMALTSTACK OP_CHECKSIG".
>

Doesn't this suffer from the standard "circular reference" problem for covenants? To pay to a utxo U1, whose scriptpubkey is a (p2wsh wrapped, say) script of: sig, op_checksig, I must create that sig, using my chosen public key, and a message which is a (signature style) hashing of a tx TX1, where an/the input to TX1 is U1, and the txid of U1 'hashes over' that script, which includes the sig we're trying to create. You can't make a hash of data which includes that hash (unless the hash fn is broken ofc).

I don't think that's affected by the later discussion here or in Zmn's response right?

Also a side detail which you might find useful in these ponderings: pubkey recovery is, as you know, possible in ECDSA but is not possible in BIP340 schnorr (which has key prefixing, i.e. the pubkey is included in the message hash binding, i.e. the e in s = k + ex), but is in the original Schnorr where only R(=kG), m are included in e. Easy to see why: from R, s and e(=H(R,m) .. easy to calculate) you can get P = (sG - R)* e^-1.
But in BIP340 Schnorr where (R, s) is published and e (=H(P, R, m)) is not, you cannot reconstruct e and so can only calculate e*P, which by DL assumption does not reveal P. Another way to put it is: if you made up a random R, s you wouldn't be able to find the right 'P' to put into e=H(P, R, m) so that the same P came out, and so that the sig actually verifies.

Cheers,
waxwing/AdamISZ