KomodoPlatform / komodo

Komodo
https://komodoplatform.com/en/
Other
119 stars 97 forks source link

Change CC Vout to make Eval code visible #323

Open ssadler opened 4 years ago

ssadler commented 4 years ago

We can't currently validate a CC VOUT, because it is a hash of an eval code which we need to validate, and a pubkey which we might not know.

Potential solutions:

  1. Include the pubkey unhashed someplace so that the cc vout can be validated. Upsides: Don't need to change the vouts Downsides: It's 32/33 bytes of redundant weight, and it reveals the pubkey which is not always desirable.

  2. Encode the fulfillment (without a sig) instead of the condition in the scriptpubkey. Upsides: Conceptual simplicity. Downsides: Not necessarily desirable from an implementation perspective, as CC expects to encounter a signature in the fulfillment, so you need to hack around that somehow.

  3. Add OP_EVAL opcode to a regular p2pkh (p2pkh+eval), ie: OP_DUP OP_HASH160 {addresshash} OP_EQUALVERIFY OP_CHECKSIGVERIFY {evalcode} OP_EVAL. This will be a new Opcode which pops the evalcode from the stack and returns true or false. OP_CHECKSIG also needs to be switched out with OP_CHECKSIGVERIFY so it bails if the signature is wrong. Upsides: Conceptual simplicity, visible addresshash, don't actually need CC to sign. Downsides: ?

Thoughts?

Mixa84 commented 4 years ago

I vote for option 3. Don't see any downsides at the moment.

I elaborate my view on the options:

  1. Adding pubkey is in OP_DROP is easy but inefficient in my opinion as we put the pubkey in CC cond too and hash it and again adding pubkey not hashed is wasting space and then better not to hash it in first place.
  2. This could be ok solution but I think it will be biggest effort to change CC for this. For both 1. and 2. we actually don't need the pubkey so much but we want to know does the vout stays in eval code it needs to stay and not so destination pubkey.
  3. So this would be the best option. In cases we need the pubkey we already put destination pubkey in opret and then compare specific vout to see if it goes to that pubkey.
Alrighttt commented 4 years ago
  1. This will require more than 33 bytes. It will require at least something along the lines of: <hashed cond> OP_CRYPTOCONDITION <eval_code[s]><pubkeys><mofn><funcids><arbitary data> OP_DROP

  2. I don't understand why we would need the fulfillment without the signature in ScriptPubKey. Can it not just be the encoded condition? This is what I meant by "Basically anytime the existing code is expecting a hashed condition, provide it the encoded condition and simply hash it before plugging it into existing code." I believe this would mean minimal changes to code for building CC ScriptSigs.

  3. This is probably the preferable solution, but be aware that it will need to support multiple eval codes in the same ScriptPubKey. I can show you examples of assets CC "dual eval" if you need. Am I correct in thinking this would not need a special(CC) signature to spend? Still trying to wrap my head around this, so I'd appreciate if you could go into more detail about what this would mean for ScriptSigs. I believe this also interferes with the "CC address" concept although it shouldn't be too hard to rework it.

ssadler commented 4 years ago

@Alrighttt

Correct, the signature would be a regular p2pkh sig.

Could you elaborate re "dual eval"?

Alrighttt commented 4 years ago
{
    "type": "threshold-sha-256",
    "threshold":    3,
    "subfulfillments":  [{
            "type": "eval-sha-256",
            "code": "5A"
        }, {
            "type": "eval-sha-256",
            "code": "8g"
        }, {
            "type": "threshold-sha-256",
            "threshold":    1,
            "subfulfillments":  [{
                    "type": "secp256k1-sha-256",
                    "publicKey":    "03682B255C40D0CDE8FAEE381A1A50BBB89980FF24539CB8518E294D3A63CEFE12"
                }]
        }]
}

This is an example of a "dual eval" condition. These are used if you need to check a CC spend against two(or more) sets of validation. For example, the heir CC supports using tokens. The condition will include both heir eval and tokens eval.

ssadler commented 4 years ago

Interesting, so what should we do about that? The OP_EVAL opcode could expect a serialized vector of eval codes, would that be a good idea?

Alrighttt commented 4 years ago

Yes, that seems sensible. We also use multisigs pretty extensively. Do you intend to support p2sh?

dimxy commented 4 years ago

The option 3 seems very interesting. There are requests to interact with Antara modules from web apps. To create an Antara transaction in a web app we would need to port cryptoconditions lib in java script. So if we allow to make Antara transactions without cryptoconditions lib we would be closer to such web apps

Mixa84 commented 4 years ago

Oh, I just realized that option 3 is totaly new thing and not CC anymore. Hmmm, not sure of the downsides. One of them is that address would be the same with regular vouts so it would mix!

dimxy commented 4 years ago

Some cc modules do not need to know to which specific pubkey the cc value is sent. But it is desirable to know that it is not sent outside the scope of cc module. That is the basic check is sum(cc inputs) == sum(cc outputs). For this it is sufficient just to have the evalcode in vouts. And there are cc modules with fixed vin/vout structure (like assets). Such modules may store pubkeys in the opreturn or OP_DROP data for verification (and their devs might care about this) So I would say: we need evalcodes in vouts for all cc modules and some specific modules may have pubkeys if they need them

ssadler commented 4 years ago

To create an Antara transaction in a web app we would need to port cryptoconditions lib in java script.

@dimxy we have CC in Rust now also, can be compiled to wasm: https://github.com/KomodoPlatform/pycc/blob/master/cryptoconditions/src/condition.rs

ssadler commented 4 years ago

Oh, I just realized that option 3 is totaly new thing and not CC anymore. Hmmm, not sure of the downsides. One of them is that address would be the same with regular vouts so it would mix!

@mixa84 that's true. But hopefully wallets wouldn't mistake it for something they can naively spend. I'm not sure if it's better or worse tbh.

ssadler commented 4 years ago

@Alrighttt: multisigs, p2sh could all be supported, it's just a bit more work in standard.cpp.

Mixa84 commented 4 years ago

@ssadler I wouldn't take a chance to mix it with regular vouts. They should be special case!

dimxy commented 4 years ago

Considering spam attacks on addresses it might be preferable for one pubkey to have several addresses for each cc module than always the same address

dimxy commented 4 years ago

@ssadler I wouldn't take a chance to mix it with regular vouts. They should be special case!

I believe it will be still a new script type as it is not strictly either p2pk or p2pkh

Alrighttt commented 4 years ago

The "CC address" concept can simply be reused as is for all ScriptPubKeys including OP_EVAL

https://gist.github.com/Alrighttt/76cbf4df35fc80ab2bb2b72d74c43fba

It's dead simple. It just turns an arbitrary ScriptPubKey into a unique address. As long as the ScriptPubKey is consistent, it will produce the same "CC address".

Alrighttt commented 4 years ago

While we're here, we should ask ourselves if we even want "CC addresses". Is there no better way of indexing utxos? The CC address concept is clever, but it comes with plenty of drawbacks.

These addresses are not visually distinguishable from normal addresses. This has caused confusion in the past.

In some cases, they permanently slow down the function of CCs. Eg: Doing for loops against all utxos owned by a CC address.

There is no guarantee that utxos sent to them have been validated. If a CC must iterate over utxos owned by a CC address, the CC must re-validate each utxo before it can be sure the utxo is what it seems to be.

ssadler commented 4 years ago

@Alrighttt yes, there will be a DB for this.

Are we decided on #3 then? Does anyone fancy having a go at implementing it?

Mixa84 commented 4 years ago

Have we considred 4), just adding evalcode(s) to vout so we can trigger validation and everything stays the same. I think we don't need the pubkey so much if we have eval code and can check if the vout goes to correct eval code. In cases we really need pubkey those vouts can have pubkey in OP_DROP but this won't be the case for most CCs so there is not much harm with readding the pubkey that is already hashed. @ssadler @dimxy @jl777 @Alrighttt BTW dont use # for numbering as it links to pull requests! :P

dimxy commented 4 years ago

I think we don't need pubkeys as a mandatory property, presence of evalcode is enough to check that cc value does not go out of cc module scope. Plus, in many cases the pubkey might be implied like in assets cc when coins are locked on the global pk always on vout0

ssadler commented 4 years ago

Ok so we came across some new options, since we might want to keep CC for more complex n-of-m cases.

In both cases, the condition binary in the ScriptPubKey is prefixed with a character (eg 'M') to indicate that it's mixed mode.

  1. Partially visible CC tree

Instead of encoding a condition fingerprint in the ScriptPubKey, a fulfillment is encoded and it's possible to specify which branches are fingerprints and which are not, for example:

CC* cond = CCNewThreshold(2, [
    CCNewEval("somecode"),
    CCHashed(CCNewThreshold(...))
]);
vec<uint8_t> mixedCond = cc_encodeMixed(cond);
mixedCond.insert(0, 'M'); // for ScriptPubKey

Advantages: Flexibility Disadvantage: Edit CC library, eval codes appear twice (in SPK and SSIG)

  1. Separate eval codes from CC binary but keep single payload

It's basically the OP_EVAL idea but hacked to make it easier to implement (no new opcode).

In this case, ScriptPubKey stays the same except the condition binary has a special format which is decoded separately:

vec<evalCode> evalCodes;
if (condBin[0] == 'M') {
    condBin.pop(0);
    E_UNMARSHAL(condBin, ss >> evalCodes; ss >> condBin);
}
// process evalcodes separately

Advantages: Simplicity, eval codes only included in SPK, no edit CC libary Disadvantages: Not as flexible as mixed mode CC

Mixa84 commented 4 years ago

My big vote is for 1. We keep the CC structure, just expose the part we need to have validation triggered on CC vout too.

Mixa84 commented 4 years ago

So, as we discussed today and realized that 1. needs heavy changes of CC core we agreed to instead go with 2. I will start modifying the code and we'll see if anything else will be a problem!

Alrighttt commented 4 years ago

@dimxy

I think we don't need pubkeys as a mandatory property, presence of evalcode is enough to check that cc value does not go out of cc module scope.

how is it possible to check a vout is to a specific eval code without having all the info needed to recreate it?

dimxy commented 4 years ago

how is it possible to check a vout is to a specific eval code without having all the info needed to recreate it?

we are going to put evalcodes into cc vouts unencoded

Alrighttt commented 4 years ago

how is it possible to check a vout is to a specific eval code without having all the info needed to recreate it?

we are going to put evalcodes into cc vouts unencoded

I had a chat with scott about this. I wasn't aware it would execute the plaintext eval code's validation along with each eval code validation in the hashed cond. This seems like it will work. Will give it some thought over the next couple days.

Mixa84 commented 4 years ago

how is it possible to check a vout is to a specific eval code without having all the info needed to recreate it?

we are going to put evalcodes into cc vouts unencoded

I had a chat with scott about this. I wasn't aware it would execute the plaintext eval code's validation along with each eval code validation in the hashed cond. This seems like it will work. Will give it some thought over the next couple days.

It won't be eval code in plain with eval codes in hashed conds. Just eval codes in plain, removing them out from CC condition.

Mixa84 commented 4 years ago

So to summarize current status, we went for option 1 in the end as it was possible to do it. The eval code part is not encrypted so it is visible in scriptPubkey and the whole threshold which holds the pubkeys and how much it needs to have in order to pass is encrypted with CC Anon object.

Currently we are testing this approach and making it trigger validation on vout so we can see does it fits the needs for CC correctly.