Good morning Pieter and Tim and all,
My understanding is that the idea now being discussed by Pieter and Tim is that
the Graftroot signature is not `sign(P, script)` but instead `sign(P,
sighash(tx))`, where `tx` is an "ordinary" transaction that spends the outpoint
that pays to `P`, and a single output whose `scriptPubKey` is the Graftroot
`script` and contains the entire value of the outpoint, and `sighash()` is the
standard SegWit transaction digest algorithm used for signing (and is affected
by other flags in the signature).
This has the advantage that the Graftroot signature commits to a single
outpoint and cannot be used to spend all outpoints that happen to pay to the
same `P` public key.
However I believe the ability to "immanentize" a Graftroot signature as a
signature for a 1-input 1-output transaction is unsafe (so a Graftroot
signature should probably not be "the same" as a signature for a 1-input
1-output transaction like the above).
Let us consider a simple CoinSwap protocol. Let us focus on one half of the
procedure, which is a simple ZKCP, i.e. Alice pays Bob for a hash preimage,
with a timeout imposed so that Bob needs to provide the preimage, within a
specified time.
1. Alice and Bob generate a shared public key P which requires k_a (Alice
secret key) and k_b (Bob secret key) to sign.
2. Alice creates but does not sign a funding transaction that pays to public
key P and gives its txid to Bob. Alice also provides a standard P2WPKH return
address that Alice controls.
3. Bob creates a `nLockTime`-encumbered transaction (the timeout backoff
transaction) on the agreed timeout, spending the above txid outpoint to the
Alice return address, and provides its half of the signature to P signing the
timeout backoff transaction to Alice.
4. Alice keeps the above signature (verifying it is to the correct `nLockTime`
and Alice return address), then signs and broadcasts the funding transaction.
Both wait for the funding transaction to confirm deeply.
5. Alice then signs a Graftroot to the script `{ OP_HASH <hash> OP_EQUALVERIFY
<P_b> OP_CHECKSIG }` and gives its half of the signature to P signing the
Graftroot to Bob. Bob keeps this signature.
6. Bob provides the preimage to the hash directly to Alice and a standard
P2WPKH destination address that Bob controls.
7. Alice then signs a direct spend of the funding transaction outpoint (one
that is not encumbered by `nLockTime`), spending the funding txid outpoint to
the Bob destination address, and provides its half of the signature to P
signing this transaction. This completes Alice participation in the protocol
(it has now received the preimage).
8. Bob completes the signature to the destination transaction and broadcasts
it to the blockchain layer.
If Alice or Bob stalls at step 5 or earlier then the transaction does not occur
(Alice does not learn the preimage, Bob gets no money).
If Bob stalls at step 6, Alice can use the timeout backoff.
If Alice stalls at step 7, Bob can use the Graftroot signed at step 5 to claim
its funds as long as the timeout is not reached.
Now if Graftroot signature is "actually" just a standard signature of a
transaction that is elided from the blockchain, however, it means that this
elided transaction can be immanentized on the blockchain with the specified
script. Even if this transaction has e.g. no fee then Bob could collude with a
miner via sidefees to get the (valid) transaction onchain.
So Bob could take the signature made at 5 to create a transaction spending to
the specified script, and prevent Alice from claiming the funds using the
timeout backoff transaction. Then Bob forever controls the UTXO and Alice
cannot back out of the transaction, so even if the knowledge of the preimage
ceases to be interesting, Alice has already paid Bob and Bob can provide the
preimage at its leisure rather than constrained by the timeout.
Thus we should somehow disallow immanentizing the Graftroot signature.
An idea is that the Graftroot signature should sign a transaction with a
specific special `nVersion`, that is then soft-forked to be invalid onchain
(i.e. the `nVersion` is reserved for Graftroot and it is invalid for a
transaction onchain to use that `nVersion`). So the Graftroot signature can be
used as a Graftroot spend, but not as a immanentized signature on an actual
onchain transaction that could disable the timeout backoff transaction.
Utilities that can sign an arbitrary message using your private keys could
check if the first four bytes match the Graftroot `nVersion` and refuse to sign
such messages to prevent inadvertently giving a Graftroot signature.
Alternatively, we note that the "transaction" signed by Graftroot will not be
referred to onchain anyway, and we could use a completely different `sighash()`
algorithm, e.g. it could just be the outpoint being spent and the script to be
executed, i.e. `sign(P, concat(txid, outnum, script))`. This reduces code
reuse, though.
Regards,
ZmnSCPxj
_______________________________________________
bitcoin-dev mailing list
[email protected]
https://lists.linuxfoundation.org/mailman/listinfo/bitcoin-dev