From e625be68a90373527085b8c06b9f88fe26666f46 Mon Sep 17 00:00:00 2001 From: Scott Sadler Date: Fri, 6 Apr 2018 02:55:47 -0300 Subject: [PATCH] allow larger PUSHDATA for CC fulfillment --- src/komodo_cc.cpp | 41 +++++++++++++++++++++-- src/komodo_cc.h | 10 ++++++ src/script/interpreter.cpp | 38 ++++++++++++++++++++- src/script/script.h | 3 ++ src/test-komodo/test_cryptoconditions.cpp | 27 +++++++++++++++ 5 files changed, 116 insertions(+), 3 deletions(-) diff --git a/src/komodo_cc.cpp b/src/komodo_cc.cpp index e7b166eba..1ebcd7e89 100644 --- a/src/komodo_cc.cpp +++ b/src/komodo_cc.cpp @@ -32,6 +32,43 @@ bool IsSignedCryptoCondition(const CC *cond) } +static unsigned char* CopyPubKey(CPubKey pkIn) +{ + unsigned char* pk = (unsigned char*) malloc(33); + memcpy(pk, pkIn.begin(), 33); // TODO: compressed? + return pk; +} + + +CC* CCNewThreshold(int t, std::vector v) +{ + CC *cond = cc_new(CC_Threshold); + cond->threshold = t; + cond->size = v.size(); + cond->subconditions = (CC**) calloc(v.size(), sizeof(CC*)); + memcpy(cond->subconditions, v.data(), v.size() * sizeof(CC*)); + return cond; +} + + +CC* CCNewSecp256k1(CPubKey k) +{ + CC *cond = cc_new(CC_Secp256k1); + cond->publicKey = CopyPubKey(k); + return cond; +} + + +CC* CCNewEval(std::string method, std::vector paramsBin) +{ + CC *cond = cc_new(CC_Eval); + strcpy(cond->method, method.data()); + cond->paramsBin = (unsigned char*) malloc(paramsBin.size()); + memcpy(cond->paramsBin, paramsBin.data(), paramsBin.size()); + cond->paramsBinLength = paramsBin.size(); + return cond; +} + CScript CCPubKey(const CC *cond) { @@ -43,8 +80,8 @@ CScript CCPubKey(const CC *cond) CScript CCSig(const CC *cond) { - unsigned char buf[1000]; - size_t len = cc_fulfillmentBinary(cond, buf, 1000); + unsigned char buf[10000]; + size_t len = cc_fulfillmentBinary(cond, buf, 10000); auto ffill = std::vector(buf, buf+len); ffill.push_back(1); // SIGHASH_ALL return CScript() << ffill; diff --git a/src/komodo_cc.h b/src/komodo_cc.h index 78cb4401a..af9efef1c 100644 --- a/src/komodo_cc.h +++ b/src/komodo_cc.h @@ -1,6 +1,7 @@ #ifndef KOMODO_CC_H #define KOMODO_CC_H +#include "pubkey.h" #include "script/script.h" #include "cryptoconditions/include/cryptoconditions.h" @@ -32,6 +33,15 @@ bool IsSupportedCryptoCondition(const CC *cond); bool IsSignedCryptoCondition(const CC *cond); +/* + * Construct crypto conditions + */ +CC* CCNewPreimage(std::vector preimage); +CC* CCNewEval(std::string method, std::vector paramsBin); +CC* CCNewSecp256k1(CPubKey k); +CC* CCNewThreshold(int t, std::vector v); + + /* * Turn a condition into a scriptPubKey */ diff --git a/src/script/interpreter.cpp b/src/script/interpreter.cpp index 31a7fdbd0..5438102c3 100644 --- a/src/script/interpreter.cpp +++ b/src/script/interpreter.cpp @@ -1372,6 +1372,37 @@ bool TransactionSignatureChecker::CheckLockTime(const CScriptNum& nLockTime) con } +/* + * Allow larger opcode in case of crypto condition scriptSig + */ +bool EvalCryptoConditionSig( + vector >& stack, + const CScript& scriptSig, + ScriptError* serror) +{ + CScript::const_iterator pc = scriptSig.begin(); + opcodetype opcode; + valtype vchPushValue; + set_error(serror, SCRIPT_ERR_UNKNOWN_ERROR); + + if (!scriptSig.GetOp(pc, opcode, vchPushValue)) + return set_error(serror, SCRIPT_ERR_BAD_OPCODE); + + if (opcode == 0 || opcode > OP_PUSHDATA4) + return set_error(serror, SCRIPT_ERR_INVALID_STACK_OPERATION); + + if (pc != scriptSig.end()) + return set_error(serror, SCRIPT_ERR_INVALID_STACK_OPERATION); + + if (vchPushValue.size() > MAX_SCRIPT_CRYPTOCONDITION_FULFILLMENT_SIZE) + return set_error(serror, SCRIPT_ERR_PUSH_SIZE); + + stack.push_back(vchPushValue); + + return true; +} + + bool VerifyScript( const CScript& scriptSig, const CScript& scriptPubKey, @@ -1387,7 +1418,12 @@ bool VerifyScript( } vector > stack, stackCopy; - if (!EvalScript(stack, scriptSig, flags, checker, consensusBranchId, serror)) + if (IsCryptoConditionsEnabled() && scriptPubKey.IsPayToCryptoCondition()) { + if (!EvalCryptoConditionSig(stack, scriptSig, serror)) + // serror is set + return false; + } + else if (!EvalScript(stack, scriptSig, flags, checker, consensusBranchId, serror)) // serror is set return false; if (flags & SCRIPT_VERIFY_P2SH) diff --git a/src/script/script.h b/src/script/script.h index b7442a419..6b8c07b07 100644 --- a/src/script/script.h +++ b/src/script/script.h @@ -19,6 +19,9 @@ static const unsigned int MAX_SCRIPT_ELEMENT_SIZE = 520; // bytes +// Max size of pushdata in a CC sig in bytes +static const unsigned int MAX_SCRIPT_CRYPTOCONDITION_FULFILLMENT_SIZE = 2048; + // Maximum script length in bytes static const int MAX_SCRIPT_SIZE = 10000; diff --git a/src/test-komodo/test_cryptoconditions.cpp b/src/test-komodo/test_cryptoconditions.cpp index f22d50be3..6f31914df 100644 --- a/src/test-komodo/test_cryptoconditions.cpp +++ b/src/test-komodo/test_cryptoconditions.cpp @@ -199,3 +199,30 @@ TEST_F(CCTest, testCryptoConditionsDisabled) ASSETCHAINS_CC = 0; ASSERT_FALSE(Verify(cond)); } + + +TEST_F(CCTest, testLargeCondition) +{ + CC *cond; + ScriptError error; + CMutableTransaction mtxTo; + + auto Verify = [&] (const CC *cond) { + CAmount amount; + CTransaction txTo(mtxTo); + PrecomputedTransactionData txdata(txTo); + auto checker = ServerTransactionSignatureChecker(&txTo, 0, amount, false, txdata); + return VerifyScript(CCSig(cond), CCPubKey(cond), 0, checker, 0, &error); + }; + + std::vector ccs; + for (int i=0; i<18; i++) { + ccs.push_back(CCNewSecp256k1(notaryKey.GetPubKey())); + } + cond = CCNewThreshold(16, ccs); + CCSign(mtxTo, cond); + EXPECT_EQ("(16 of 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,A5,A5)", + CCShowStructure(CCPrune(cond))); + EXPECT_EQ(1744, CCSig(cond).size()); + ASSERT_TRUE(Verify(cond)); +}