rgb-archive / spec

[OLD!] RGB Protocol specifications for Bitcoin-based digital assets
https://rgb-org.github.io/
147 stars 26 forks source link

Possible conflict of pay-to-contract schemes with Taproot #61

Closed ZmnSCPxj closed 5 years ago

ZmnSCPxj commented 6 years ago

As the subject says, pay-to-contract schemes may conflict with Taproot in the future, if extended naively to a future Bitcoin version with Taproot support.

Proofs may themselves be marshalled into a form which can also be read as Bitcoin SCRIPT. This would allow a scammer to induce a victim to construct a proof that can be reinterpreted as a Bitcoin SCRIPT which the scammer may know how to solve, allowing the scammer to burn the colored asset and steal the backing Bitcoin UTXO via the always-enabled Taproot branch. I have not seen spec about proof marshalling (perhaps, not yet created?), but this is care point.

An idea, is to make an OP_RETURN byte (0x6A) be the first byte in every marshalling of a proof. Thus when reinterpreted as Bitcoin SCRIPT, the first instruction, is an OP_RETURN, which prevents the proof from being reinterpreted as a Bitcoin SCRIPT that can be solved, as OP_RETURN scripts are unsolveable.

(Another mitigation is to make the backing Bitcoin funds so small as to be not worth the effort of stealing, but this may conflict with your intended plan, for using also a UTXO to back LN channels with both Bitcoin and asset)

(also this may be an argument against an always-enabled Taproot; possibly we could add a flag or marker, in the contract space, which selects "domain", and Bitcoin Taproot is simply an additional domain)

Care must still be taken in future. Other schemes that use pay-to-contract may also conflict with RGB usage in the same manner: a proof marshalling under RGB may be reinterpreted as a contract in another scheme, which may lead to victims assuming they have proofs under one system and then inadvertently signing off on a proof/contract for another system.

afilini commented 6 years ago

I really have to catch up on Taproot since I don't know much about it, but my initial impression is that doing this would require to break an hash function: in our pay-to-contract scheme we would only commit to the hash of a proof, and many of its fields are controlled by the "sender" (which, if I understood correctly, should be the victim in the model you described).

So, the attacker would have to craft and "address" such that, once embedded into a proof (possibly with some data he doesn't know yet) will make the hash of the proof an executable, malicious, Bitcoin SCRIPT.

Now I'll go study and come back later when I fully understand how Taproot works ;)

PS: if you have any good references/articles please let me know here or via DM at twitter.com/afilini

afilini commented 6 years ago

Oh, and about your suggestion of making small Bitcoin amounts: I was thinking about it while writing the slides for the Berlin Lightning hackday a couple of days ago.. Speaking for the Lightning part, my idea was to force the payment of fees on the underlying Bitcoin layer, to reduce the amount of data we have to gossip around (we already have Bitcoin fees and asset/Bitcoin exchange rate).

In this model, in order to have proportional fees, you would need to use the exchange rate to estimate the value of the asset being moved in Bitcoin, and then apply the Bitcoin proportional fee to it.

If this is really what we end up doing (I honestly don't really like it but I don't have any other solution yet) you would need pretty "big" Bitcoin channels to transport "big" RGB proofs, otherwise you wouldn't have enough liquidity to move the tokens.


Link to the talk if you are interested: https://youtu.be/QrX1SpD6l9g?t=5h9m47s

ZmnSCPxj commented 6 years ago

but my initial impression is that doing this would require to break an hash function: in our pay-to-contract scheme we would only commit to the hash of a proof

It may be possible to do so opportunistically. For instance, if the first two bytes of the hash are 0x4C 0x1E (OP_PUSHDATA1 30: push the next 30 bytes in the script as a single word on the stack), this results with high probability to a SCRIPT that pushes a truthy (nonzero) value on the stack, and is therefore anyone-can-spend with an empty witness stack. About 1 out of 65536 contracts will hash to a value that starts with those two bytes. Other reinterpretations to OP_PUSHDATA* opcodes may also be possible

Of course, it is possible that Taproot will also use a hash to further protect the Bitcoin SCRIPT and make such reinterpretation much harder with high probability. I have not seen enough details on the low-level of Taproot myself, perhaps it may also use a hash around the script before concatenating with the pubkey and hashing again. It may be useful to ask gmax or similar if this concern is unfounded.

ZmnSCPxj commented 6 years ago

it is possible that Taproot will also use a hash to further protect the Bitcoin SCRIPT and make such reinterpretation much harder with high probability

No, I apologize, I am being daft here. If Taproot does use a hash and you also use a hash, and it is the same hash function, then the direct serialization of your proof might be reinterpreted as a direct serialization of a Bitcoin SCRIPT, and various values and codes you use in your proofs may correspond to particular Bitcoin SCRIPT opcodes that could lead to an easily-spendable Bitcoin SCRIPT.

In short: you may need to look very well into any concrete Taproot proposal that comes up in the future (there are none yet other than basic sketches).

afilini commented 6 years ago

Yes, if the hash function is the same (and I think it would be likely), then it could become an issue.

As I said before, I think it would be hard to force the victim into unknowingly pay to a precise SCRIPT, but as you pointed out in many cases a big "family" of SCRIPTs can make you loose funds.

I guess I will keep this open as a reminder and to see if someone else has an idea to propose. Once Taproot will be finalized we will make sure there are no conflicts.

ZmnSCPxj commented 6 years ago

Taproot is the most obvious, but, if other schemes also use pay-to-contract similarly, again a UTXO committing to an RGB proof may itself be reinterpreted as committing to a different pay-to-contract scheme contract. I have a thread on bitcoin-dev awaiting moderation about the reinterpretation problem. I believe the general solution is to adjust the tweak to:

Q = P + H(P || S || C) * G

Where S is a scheme ID (32 bytes/256 bits) that is unique to the scheme. The contract C is to be interpreted according to the scheme S.

In short, pay-to-contract must commit, not only to the contract itself, but to how the contract is to be interpreted.

ZmnSCPxj commented 6 years ago

Thread on bitcoin-dev: https://lists.linuxfoundation.org/pipermail/bitcoin-dev/2018-September/016354.html

ajtowns commented 5 years ago

I think it might make more sense to have the taproot-based p2c scheme be:

base pubkey: P
p2c: Q = P + H("rgb" || P || contract)*G
taproot scriptPubKey: R = Q + H(Q || "OP_RETURN")*G

So R = P + H("rgb"||P||contract)*G + H(Q||"OP_RETURN")*G

ZmnSCPxj commented 5 years ago

That certainly seems a plausible solution aj.

ZmnSCPxj commented 5 years ago

A possibility when using Taproot is to merge the OP_RETURN and pay-to-contract commitments, by having one script branch in the Taprooted MAST be an OP_RETURN script with the contract in the OP_RETURN. "Real" script alternatives can be placed in other leaves of the MAST; we simply add an additional one to contain the RGB contract.

Still, we must be careful that a RGB contract serialization may be interpretable as the serialization of another pay-to-contract system using the same technique. So we should use tagged sha just as in bip-taproot.

dr-orlovsky commented 5 years ago

Thread on bitcoin-dev: https://lists.linuxfoundation.org/pipermail/bitcoin-dev/2018-September/016354.html

I do like this proposal, it looks workable @ZmnSCPxj, have you had any further thoughts on the topic since then?

ZmnSCPxj commented 5 years ago

Comment by ajtowns seems better. Alternatively, given current taproot proposal it would be possible to embed a hash of the RGB contract in a taproot branch that is OP_RETURN, with a RGB-specific tagged hash function as per bip-taproot. The bip-taprrot tagged hash is effectively what I propose, i.e. making a prefix that is specific to each use case, except the bip-taproot tagged hash fleshes it out and considers efficient implementations.

dr-orlovsky commented 5 years ago

Alternatively, given current taproot proposal it would be possible to embed a hash of the RGB contract in a taproot branch that is OP_RETURN, with a RGB-specific tagged hash function as per bip-taproot.

Looks cool and sounds like a new commitment scheme for RGB. @giacomozucco, @afilini what do you think?

Comment by @ajtowns seems better.

Emm... I don't get why P + H("rgb" || P || contract)*G is anyhow better than P + H(P || contract)*G...

inaltoasinistra commented 5 years ago

Alternatively, given current taproot proposal it would be possible to embed a hash of the RGB contract in a taproot branch that is OP_RETURN, with a RGB-specific tagged hash function as per bip-taproot.

I see a problem here: double spend. It is possible to commit more then one RGB proofs into the taproot scripts tree. I don't see trivial solutions without affect privacy (i.e. include all the taproot scripts into the RGB proof)

ZmnSCPxj commented 5 years ago

Emm... I don't get why P + H("rgb" || P || contract)*G is anyhow better than P + H(P || contract)*G...

The original problem pointed out that multiple pay-to-contract schemes may exist, not just RGB.

The extra H("rgb" | is intended to disambiguate, so that even if RGB contracts can written whose serialization is equivalent to the serialization of a contract in a different pay-to-contract scheme, if the other scheme uses a different prefix, it cannot be used to commit to multiple pay-to-contract schemes.

I see a problem here: double spend. It is possible to commit more then one RGB proofs into the taproot scripts tree.

You are correct and indeed the @ajtowns solution is strictly superior, as it avoids this issue.

dr-orlovsky commented 5 years ago

Got it and agree. Since I'm doing implementation of the complete RGB spec from scratch (here https://github.com/dr-orlovsky/rgb-rust) I'll add this to the code and also will do a PR to the spec itself.

dr-orlovsky commented 5 years ago

Seems like we need to add "RGB" prefix into the contract serialization as well (additionally to the actual PK tweak), in order to make the serialized contract code unambiguous. This prefix has to be included into the hash of the contract. I've already made this in code (see commit https://github.com/dr-orlovsky/rgb-rust/commit/7a1e1cec43e6c2250fc752449fd0b5d0cf721716 above). I will add this to the spec as well.

dr-orlovsky commented 5 years ago

Closing, discussion shall continue in the new PR #73