cpp test suite for cryptoconditions integration

This commit is contained in:
Scott Sadler
2018-04-01 21:18:01 -03:00
parent 563581aff4
commit 4c121ffdb0
19 changed files with 336 additions and 465 deletions

View File

@@ -620,9 +620,10 @@ endif
@test -f $(PROTOC)
$(AM_V_GEN) $(PROTOC) --cpp_out=$(@D) --proto_path=$(abspath $(<D) $<)
#if ENABLE_TESTS
if ENABLE_TESTS
include Makefile.ktest.include
#include Makefile.test.include
#include Makefile.gtest.include
#endif
endif
include Makefile.zcash.include

View File

@@ -0,0 +1,14 @@
TESTS += komodo-test
bin_PROGRAMS += komodo-test
# tool for generating our public parameters
komodo_test_SOURCES = \
test-komodo/main.cpp \
test-komodo/test_cryptoconditions.cpp
komodo_test_CPPFLAGS = $(komodod_CPPFLAGS)
komodo_test_LDADD = -lgtest $(komodod_LDADD)
komodo_test_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS) -static

View File

@@ -9,9 +9,9 @@
*/
bool EvalConditionValidity(const CC *cond, const CTransaction *txTo, int nIn)
{
if (strcmp(cond->method, "testEval") == 0) {
if (strcmp(cond->method, "TestEval") == 0) {
return cond->paramsBinLength == 8 &&
memcmp(cond->paramsBin, "testEval", 8) == 0;
memcmp(cond->paramsBin, "TestEval", 8) == 0;
}
if (strcmp(cond->method, "ImportPayout") == 0) {

View File

@@ -26,6 +26,7 @@ enum CCTypeId {
};
/*
* Evaliliary verification callback
*/
@@ -83,17 +84,17 @@ int cc_signTreeSecp256k1Msg32(CC *cond, const unsigned char *private
size_t cc_conditionBinary(const CC *cond, unsigned char *buf);
size_t cc_fulfillmentBinary(const CC *cond, unsigned char *buf, size_t bufLength);
static int cc_secp256k1VerifyTreeMsg32(const CC *cond, const unsigned char *msg32);
struct CC* cc_conditionFromJSON(cJSON *params, unsigned char *err);
struct CC* cc_conditionFromJSONString(const unsigned char *json, unsigned char *err);
struct CC* cc_conditionFromJSON(cJSON *params, char *err);
struct CC* cc_conditionFromJSONString(const char *json, char *err);
struct CC* cc_readConditionBinary(const unsigned char *cond_bin, size_t cond_bin_len);
struct CC* cc_readFulfillmentBinary(const unsigned char *ffill_bin, size_t ffill_bin_len);
struct cJSON* cc_conditionToJSON(const CC *cond);
unsigned char* cc_conditionToJSONString(const CC *cond);
unsigned char* cc_conditionUri(const CC *cond);
unsigned char* cc_jsonRPC(unsigned char *request);
unsigned long cc_getCost(const CC *cond);
enum CCTypeId cc_typeId(const CC *cond);
char* cc_conditionToJSONString(const CC *cond);
char* cc_conditionUri(const CC *cond);
char* cc_jsonRPC(char *request);
char* cc_typeName(const CC *cond);
enum CCTypeId cc_typeId(const CC *cond);
unsigned long cc_getCost(const CC *cond);
uint32_t cc_typeMask(const CC *cond);
void cc_free(struct CC *cond);

View File

@@ -16,7 +16,7 @@
#include <malloc.h>
static struct CCType *typeRegistry[] = {
struct CCType *CCTypeRegistry[] = {
&cc_preimageType,
&cc_prefixType,
&cc_thresholdType,
@@ -28,7 +28,7 @@ static struct CCType *typeRegistry[] = {
};
static int typeRegistryLength = sizeof(typeRegistry) / sizeof(typeRegistry[0]);
int CCTypeRegistryLength = sizeof(CCTypeRegistry) / sizeof(CCTypeRegistry[0]);
void appendUriSubtypes(uint32_t mask, unsigned char *buf) {
@@ -37,10 +37,10 @@ void appendUriSubtypes(uint32_t mask, unsigned char *buf) {
if (mask & 1 << i) {
if (append) {
strcat(buf, ",");
strcat(buf, typeRegistry[i]->name);
strcat(buf, CCTypeRegistry[i]->name);
} else {
strcat(buf, "&subtypes=");
strcat(buf, typeRegistry[i]->name);
strcat(buf, CCTypeRegistry[i]->name);
append = 1;
}
}
@@ -48,7 +48,7 @@ void appendUriSubtypes(uint32_t mask, unsigned char *buf) {
}
unsigned char *cc_conditionUri(const CC *cond) {
char *cc_conditionUri(const CC *cond) {
unsigned char *fp = cond->type->fingerprint(cond);
if (!fp) return NULL;
@@ -158,9 +158,9 @@ unsigned long cc_getCost(const CC *cond) {
CCType *getTypeByAsnEnum(Condition_PR present) {
for (int i=0; i<typeRegistryLength; i++) {
if (typeRegistry[i] != NULL && typeRegistry[i]->asnType == present) {
return typeRegistry[i];
for (int i=0; i<CCTypeRegistryLength; i++) {
if (CCTypeRegistry[i] != NULL && CCTypeRegistry[i]->asnType == present) {
return CCTypeRegistry[i];
}
}
return NULL;
@@ -245,7 +245,7 @@ CC *cc_readConditionBinary(const unsigned char *cond_bin, size_t length) {
asn_dec_rval_t rval;
rval = ber_decode(0, &asn_DEF_Condition, (void **)&asnCond, cond_bin, length);
if (rval.code != RC_OK) {
printf("Failed reading condition binary\n");
fprintf(stderr, "Failed reading condition binary\n");
return NULL;
}
CC *cond = mkAnon(asnCond);

View File

@@ -20,13 +20,13 @@ extern "C" {
* Condition Type */
typedef struct CCType {
int typeId;
unsigned char name[100];
char name[100];
Condition_PR asnType;
int (*visitChildren)(CC *cond, CCVisitor visitor);
unsigned char *(*fingerprint)(const CC *cond);
unsigned long (*getCost)(const CC *cond);
uint32_t (*getSubtypes)(const CC *cond);
CC *(*fromJSON)(const cJSON *params, unsigned char *err);
CC *(*fromJSON)(const cJSON *params, char *err);
void (*toJSON)(const CC *cond, cJSON *params);
CC *(*fromFulfillment)(const Fulfillment_t *ffill);
Fulfillment_t *(*toFulfillment)(const CC *cond);
@@ -38,8 +38,8 @@ typedef struct CCType {
/*
* Globals
*/
static struct CCType *typeRegistry[];
static int typeRegistryLength;
struct CCType *CCTypeRegistry[];
int CCTypeRegistryLength;
/*
@@ -50,7 +50,7 @@ static CC *mkAnon(const Condition_t *asnCond);
static void asnCondition(const CC *cond, Condition_t *asn);
static Condition_t *asnConditionNew(const CC *cond);
static Fulfillment_t *asnFulfillmentNew(const CC *cond);
static cJSON *jsonEncodeCondition(cJSON *params, unsigned char *err);
static cJSON *jsonEncodeCondition(cJSON *params, char *err);
static struct CC *fulfillmentToCC(Fulfillment_t *ffill);
static struct CCType *getTypeByAsnEnum(Condition_PR present);
@@ -62,11 +62,11 @@ unsigned char *base64_encode(const unsigned char *data, size_t input_length);
unsigned char *base64_decode(const unsigned char *data_, size_t *output_length);
unsigned char *hashFingerprintContents(asn_TYPE_descriptor_t *asnType, void *fp);
void dumpStr(unsigned char *str, size_t len);
int checkString(const cJSON *value, unsigned char *key, unsigned char *err);
int checkDecodeBase64(const cJSON *value, unsigned char *key, unsigned char *err, unsigned char **data, size_t *size);
int jsonGetBase64(const cJSON *params, unsigned char *key, unsigned char *err, unsigned char **data, size_t *size);
int jsonGetBase64Optional(const cJSON *params, unsigned char *key, unsigned char *err, unsigned char **data, size_t *size);
void jsonAddBase64(cJSON *params, unsigned char *key, unsigned char *bin, size_t size);
int checkString(const cJSON *value, char *key, char *err);
int checkDecodeBase64(const cJSON *value, char *key, char *err, unsigned char **data, size_t *size);
int jsonGetBase64(const cJSON *params, char *key, char *err, unsigned char **data, size_t *size);
int jsonGetBase64Optional(const cJSON *params, char *key, char *err, unsigned char **data, size_t *size);
void jsonAddBase64(cJSON *params, char *key, unsigned char *bin, size_t size);
#ifdef __cplusplus

View File

@@ -34,7 +34,7 @@ static cJSON *jsonFulfillment(CC *cond) {
}
CC *cc_conditionFromJSON(cJSON *params, unsigned char *err) {
CC *cc_conditionFromJSON(cJSON *params, char *err) {
if (!params || !cJSON_IsObject(params)) {
strcpy(err, "Condition params must be an object");
return NULL;
@@ -44,10 +44,10 @@ CC *cc_conditionFromJSON(cJSON *params, unsigned char *err) {
strcpy(err, "\"type\" must be a string");
return NULL;
}
for (int i=0; i<typeRegistryLength; i++) {
if (typeRegistry[i] != NULL) {
if (0 == strcmp(typeName->valuestring, typeRegistry[i]->name)) {
return typeRegistry[i]->fromJSON(params, err);
for (int i=0; i<CCTypeRegistryLength; i++) {
if (CCTypeRegistry[i] != NULL) {
if (0 == strcmp(typeName->valuestring, CCTypeRegistry[i]->name)) {
return CCTypeRegistry[i]->fromJSON(params, err);
}
}
}
@@ -56,7 +56,7 @@ CC *cc_conditionFromJSON(cJSON *params, unsigned char *err) {
}
CC *cc_conditionFromJSONString(const unsigned char *data, unsigned char *err) {
CC *cc_conditionFromJSONString(const char *data, char *err) {
cJSON *params = cJSON_Parse(data);
CC *out = cc_conditionFromJSON(params, err);
cJSON_Delete(params);
@@ -64,7 +64,7 @@ CC *cc_conditionFromJSONString(const unsigned char *data, unsigned char *err) {
}
static cJSON *jsonEncodeCondition(cJSON *params, unsigned char *err) {
static cJSON *jsonEncodeCondition(cJSON *params, char *err) {
CC *cond = cc_conditionFromJSON(params, err);
cJSON *out = NULL;
if (cond != NULL) {
@@ -75,7 +75,7 @@ static cJSON *jsonEncodeCondition(cJSON *params, unsigned char *err) {
}
static cJSON *jsonEncodeFulfillment(cJSON *params, unsigned char *err) {
static cJSON *jsonEncodeFulfillment(cJSON *params, char *err) {
CC *cond = cc_conditionFromJSON(params, err);
cJSON *out = NULL;
if (cond != NULL) {
@@ -86,14 +86,14 @@ static cJSON *jsonEncodeFulfillment(cJSON *params, unsigned char *err) {
}
static cJSON *jsonErr(unsigned char *err) {
static cJSON *jsonErr(char *err) {
cJSON *out = cJSON_CreateObject();
cJSON_AddItemToObject(out, "error", cJSON_CreateString(err));
return out;
}
static cJSON *jsonVerifyFulfillment(cJSON *params, unsigned char *err) {
static cJSON *jsonVerifyFulfillment(cJSON *params, char *err) {
unsigned char *ffill_bin = 0, *msg = 0, *cond_bin = 0;
size_t ffill_bin_len, msg_len, cond_bin_len;
cJSON *out = 0;
@@ -121,7 +121,7 @@ END:
}
static cJSON *jsonDecodeFulfillment(cJSON *params, unsigned char *err) {
static cJSON *jsonDecodeFulfillment(cJSON *params, char *err) {
size_t ffill_bin_len;
unsigned char *ffill_bin;
if (!jsonGetBase64(params, "fulfillment", err, &ffill_bin, &ffill_bin_len))
@@ -139,7 +139,7 @@ static cJSON *jsonDecodeFulfillment(cJSON *params, unsigned char *err) {
}
static cJSON *jsonDecodeCondition(cJSON *params, unsigned char *err) {
static cJSON *jsonDecodeCondition(cJSON *params, char *err) {
size_t cond_bin_len;
unsigned char *cond_bin;
if (!jsonGetBase64(params, "bin", err, &cond_bin, &cond_bin_len))
@@ -160,7 +160,7 @@ static cJSON *jsonDecodeCondition(cJSON *params, unsigned char *err) {
}
static cJSON *jsonSignTreeEd25519(cJSON *params, unsigned char *err) {
static cJSON *jsonSignTreeEd25519(cJSON *params, char *err) {
cJSON *out = 0;
unsigned char *msg = 0, *sk = 0;
@@ -197,7 +197,7 @@ END:
}
static cJSON *jsonSignTreeSecp256k1(cJSON *params, unsigned char *err) {
static cJSON *jsonSignTreeSecp256k1(cJSON *params, char *err) {
cJSON *out = 0;
unsigned char *msg = 0, *sk = 0;
@@ -244,22 +244,22 @@ cJSON *cc_conditionToJSON(const CC *cond) {
}
unsigned char *cc_conditionToJSONString(const CC *cond) {
char *cc_conditionToJSONString(const CC *cond) {
assert(cond != NULL);
cJSON *params = cc_conditionToJSON(cond);
unsigned char *out = cJSON_Print(params);
char *out = cJSON_Print(params);
cJSON_Delete(params);
return out;
}
static cJSON *jsonListMethods(cJSON *params, unsigned char *err);
static cJSON *jsonListMethods(cJSON *params, char *err);
typedef struct JsonMethod {
unsigned char *name;
cJSON* (*method)(cJSON *params, unsigned char *err);
unsigned char *description;
char *name;
cJSON* (*method)(cJSON *params, char *err);
char *description;
} JsonMethod;
@@ -278,7 +278,7 @@ static JsonMethod cc_jsonMethods[] = {
static int nJsonMethods = sizeof(cc_jsonMethods) / sizeof(*cc_jsonMethods);
static cJSON *jsonListMethods(cJSON *params, unsigned char *err) {
static cJSON *jsonListMethods(cJSON *params, char *err) {
cJSON *list = cJSON_CreateArray();
for (int i=0; i<nJsonMethods; i++) {
JsonMethod method = cc_jsonMethods[i];
@@ -293,7 +293,7 @@ static cJSON *jsonListMethods(cJSON *params, unsigned char *err) {
}
static cJSON* execJsonRPC(cJSON *root, unsigned char *err) {
static cJSON* execJsonRPC(cJSON *root, char *err) {
cJSON *method_item = cJSON_GetObjectItem(root, "method");
if (!cJSON_IsString(method_item)) {
@@ -316,8 +316,8 @@ static cJSON* execJsonRPC(cJSON *root, unsigned char *err) {
}
unsigned char *cc_jsonRPC(unsigned char* input) {
unsigned char err[1000] = "\0";
char *cc_jsonRPC(char* input) {
char err[1000] = "\0";
cJSON *out;
cJSON *root = cJSON_Parse(input);
if (!root) out = jsonErr("Error parsing JSON request");
@@ -325,7 +325,7 @@ unsigned char *cc_jsonRPC(unsigned char* input) {
out = execJsonRPC(root, err);
if (NULL == out) out = jsonErr(err);
}
unsigned char *res = cJSON_Print(out);
char *res = cJSON_Print(out);
cJSON_Delete(out);
cJSON_Delete(root);
return res;

View File

@@ -125,7 +125,7 @@ typedef struct CCSecp256k1SigningData {
* Visitor that signs an secp256k1 condition if it has a matching public key
*/
static int secp256k1Sign(CC *cond, CCVisitor visitor) {
if (cond->type->typeId != cc_secp256k1Type.typeId) return 1;
if (cond->type->typeId != CC_Secp256k1) return 1;
CCSecp256k1SigningData *signing = (CCSecp256k1SigningData*) visitor.context;
if (0 != memcmp(cond->publicKey, signing->pk, SECP256K1_PK_SIZE)) return 1;
@@ -148,7 +148,7 @@ static int secp256k1Sign(CC *cond, CCVisitor visitor) {
* Sign secp256k1 conditions in a tree
*/
int cc_signTreeSecp256k1Msg32(CC *cond, const unsigned char *privateKey, const unsigned char *msg32) {
if (cc_typeMask(cond) & (1 << cc_preimageType.typeId)) {
if (cc_typeMask(cond) & (1 << CC_Prefix)) {
// No support for prefix currently, due to pending protocol decision on
// how to combine message and prefix into 32 byte hash
return 0;
@@ -159,7 +159,10 @@ int cc_signTreeSecp256k1Msg32(CC *cond, const unsigned char *privateKey, const u
lockSign();
int rc = secp256k1_ec_pubkey_create(ec_ctx_sign, &spk, privateKey);
unlockSign();
if (rc != 1) return 0;
if (rc != 1) {
fprintf(stderr, "Cryptoconditions couldn't derive secp256k1 pubkey\n");
return 0;
}
// serialize pubkey
unsigned char *publicKey = calloc(1, SECP256K1_PK_SIZE);

View File

@@ -44,7 +44,7 @@ static unsigned long thresholdCost(const CC *cond) {
static int thresholdVisitChildren(CC *cond, CCVisitor visitor) {
for (int i=0; i<cond->threshold; i++) {
for (int i=0; i<cond->size; i++) {
if (!cc_visit(cond->subconditions[i], visitor)) {
return 0;
}
@@ -203,7 +203,7 @@ static void thresholdToJSON(const CC *cond, cJSON *params) {
static int thresholdIsFulfilled(const CC *cond) {
int nFulfilled = 0;
for (int i=0; i<cond->threshold; i++) {
if (!cc_isFulfilled(cond->subconditions[i])) {
if (cc_isFulfilled(cond->subconditions[i])) {
nFulfilled++;
}
if (nFulfilled == cond->threshold) {

View File

@@ -141,7 +141,7 @@ void dumpStr(unsigned char *str, size_t len) {
int checkString(const cJSON *value, unsigned char *key, unsigned char *err) {
int checkString(const cJSON *value, char *key, char *err) {
if (value == NULL) {
sprintf(err, "%s is required", key);
return 0;
@@ -153,7 +153,7 @@ int checkString(const cJSON *value, unsigned char *key, unsigned char *err) {
return 1;
}
int checkDecodeBase64(const cJSON *value, unsigned char *key, unsigned char *err, unsigned char **data, size_t *size) {
int checkDecodeBase64(const cJSON *value, char *key, char *err, unsigned char **data, size_t *size) {
if (!checkString(value, key, err)) {
sprintf(err, "%s must be valid base64 string", key);
return 0;
@@ -168,7 +168,7 @@ int checkDecodeBase64(const cJSON *value, unsigned char *key, unsigned char *err
}
int jsonGetBase64(const cJSON *params, unsigned char *key, unsigned char *err, unsigned char **data, size_t *size)
int jsonGetBase64(const cJSON *params, char *key, char *err, unsigned char **data, size_t *size)
{
cJSON *item = cJSON_GetObjectItem(params, key);
if (!item) {
@@ -179,7 +179,7 @@ int jsonGetBase64(const cJSON *params, unsigned char *key, unsigned char *err, u
}
int jsonGetBase64Optional(const cJSON *params, unsigned char *key, unsigned char *err, unsigned char **data, size_t *size) {
int jsonGetBase64Optional(const cJSON *params, char *key, char *err, unsigned char **data, size_t *size) {
cJSON *item = cJSON_GetObjectItem(params, key);
if (!item) {
return 1;
@@ -188,7 +188,7 @@ int jsonGetBase64Optional(const cJSON *params, unsigned char *key, unsigned char
}
void jsonAddBase64(cJSON *params, unsigned char *key, unsigned char *bin, size_t size) {
void jsonAddBase64(cJSON *params, char *key, unsigned char *bin, size_t size) {
unsigned char *b64 = base64_encode(bin, size);
cJSON_AddItemToObject(params, key, cJSON_CreateString(b64));
free(b64);

View File

@@ -7,18 +7,6 @@ bool IsCryptoConditionsEnabled()
return 0 != ASSETCHAINS_CC;
}
// Limit acceptable condition types
// Prefix not enabled because no current use case, ambiguity on how to combine with secp256k1
// RSA not enabled because no current use case, not implemented
int CCEnabledTypes = 1 << CC_Secp256k1 | \
1 << CC_Threshold | \
1 << CC_Eval | \
1 << CC_Preimage | \
1 << CC_Ed25519;
int CCSigningNodes = 1 << CC_Ed25519 | 1 << CC_Secp256k1;
bool IsSupportedCryptoCondition(const CC *cond)
{

View File

@@ -7,6 +7,17 @@
extern int32_t ASSETCHAINS_CC;
bool IsCryptoConditionsEnabled();
// Limit acceptable condition types
// Prefix not enabled because no current use case, ambiguity on how to combine with secp256k1
// RSA not enabled because no current use case, not implemented
const int CCEnabledTypes = 1 << CC_Secp256k1 | \
1 << CC_Threshold | \
1 << CC_Eval | \
1 << CC_Preimage | \
1 << CC_Ed25519;
const int CCSigningNodes = 1 << CC_Ed25519 | 1 << CC_Secp256k1;
/*
* Check if the server can accept the condition based on it's structure / types

View File

@@ -161,7 +161,7 @@ public:
const std::vector<unsigned char>& ffillBin,
const CScript& scriptCode,
uint32_t consensusBranchId) const;
VerifyEval GetCCEval() const;
virtual VerifyEval GetCCEval() const;
};
class MutableTransactionSignatureChecker : public TransactionSignatureChecker

12
src/test-komodo/main.cpp Normal file
View File

@@ -0,0 +1,12 @@
#include "key.h"
#include "gtest/gtest.h"
#include "crypto/common.h"
int main(int argc, char **argv) {
assert(init_and_check_sodium() != -1);
ECC_Start();
testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
}

View File

@@ -0,0 +1,226 @@
#include <cryptoconditions.h>
#include <gtest/gtest.h>
#include "base58.h"
#include "key.h"
#include "komodo_cc.h"
#include "primitives/transaction.h"
#include "script/interpreter.h"
#include "script/serverchecker.h"
#define VCH(a,b) std::vector<unsigned char>(a, a + b)
std::string pubkey = "0205a8ad0c1dbc515f149af377981aab58b836af008d4d7ab21bd76faf80550b47";
std::string secret = "UxFWWxsf1d7w7K5TvAWSkeX4H95XQKwdwGv49DXwWUTzPTTjHBbU";
CKey notaryKey;
char ccjsonerr[1000] = "\0";
#define CCFromJson(o,s) \
o = cc_conditionFromJSONString(s, ccjsonerr); \
if (!o) FAIL() << "bad json: " << ccjsonerr;
CScript CCPubKey(const CC *cond) {
unsigned char buf[1000];
size_t len = cc_conditionBinary(cond, buf);
return CScript() << VCH(buf, len) << OP_CHECKCRYPTOCONDITION;
}
CScript CCSig(const CC *cond) {
unsigned char buf[1000];
size_t len = cc_fulfillmentBinary(cond, buf, 1000);
auto ffill = VCH(buf, len);
ffill.push_back(SIGHASH_ALL);
return CScript() << ffill;
}
void CCSign(CMutableTransaction &tx, CC *cond) {
tx.vin.resize(1);
PrecomputedTransactionData txdata(tx);
uint256 sighash = SignatureHash(CCPubKey(cond), tx, 0, SIGHASH_ALL, 0, 0, &txdata);
int out = cc_signTreeSecp256k1Msg32(cond, notaryKey.begin(), sighash.begin());
tx.vin[0].scriptSig = CCSig(cond);
}
class CCTest : public ::testing::Test {
protected:
static void SetUpTestCase() {
SelectParams(CBaseChainParams::REGTEST);
// Notary key
CBitcoinSecret vchSecret;
// this returns false due to network prefix mismatch but works anyway
vchSecret.SetString(secret);
notaryKey = vchSecret.GetKey();
}
virtual void SetUp() {
// enable CC
ASSETCHAINS_CC = 1;
}
};
TEST_F(CCTest, testIsPayToCryptoCondition)
{
CScript s = CScript() << VCH("a", 1);
ASSERT_FALSE(s.IsPayToCryptoCondition());
s = CScript() << VCH("a", 1) << OP_CHECKCRYPTOCONDITION;
ASSERT_TRUE(s.IsPayToCryptoCondition());
s = CScript() << OP_CHECKCRYPTOCONDITION;
ASSERT_FALSE(s.IsPayToCryptoCondition());
}
TEST_F(CCTest, testMayAcceptCryptoCondition)
{
CC *cond;
// ok
CCFromJson(cond, R"!!(
{ "type": "threshold-sha-256",
"threshold": 2,
"subfulfillments": [
{ "type": "secp256k1-sha-256", "publicKey": "AgWorQwdvFFfFJrzd5gaq1i4Nq8AjU16shvXb6+AVQtH" }
]
})!!");
ASSERT_TRUE(CCPubKey(cond).MayAcceptCryptoCondition());
// prefix not allowed
CCFromJson(cond, R"!!(
{ "type": "prefix-sha-256",
"prefix": "abc",
"maxMessageLength": 10,
"subfulfillment":
{ "type": "secp256k1-sha-256", "publicKey": "AgWorQwdvFFfFJrzd5gaq1i4Nq8AjU16shvXb6+AVQtH" }
})!!");
ASSERT_FALSE(CCPubKey(cond).MayAcceptCryptoCondition());
// has no signature nodes
CCFromJson(cond, R"!!(
{ "type": "threshold-sha-256",
"threshold": 1,
"subfulfillments": [
{ "type": "eval-sha-256", "method": "test", "params": "" },
{ "type": "eval-sha-256", "method": "test", "params": "" }
]
})!!");
ASSERT_FALSE(CCPubKey(cond).MayAcceptCryptoCondition());
}
TEST_F(CCTest, testVerifyCryptoCondition)
{
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);
};
// ok
CCFromJson(cond, R"!!({
"type": "secp256k1-sha-256",
"publicKey": "AgWorQwdvFFfFJrzd5gaq1i4Nq8AjU16shvXb6+AVQtH"
})!!");
CCSign(mtxTo, cond);
ASSERT_TRUE(Verify(cond));
// has signature nodes
CCFromJson(cond, R"!!({
"type": "threshold-sha-256",
"threshold": 1,
"subfulfillments": [
{ "type": "preimage-sha-256", "preimage": "" },
{ "type": "secp256k1-sha-256", "publicKey": "AgWorQwdvFFfFJrzd5gaq1i4Nq8AjU16shvXb6+AVQtH" }
]
})!!");
cond->threshold = 2;
CCSign(mtxTo, cond);
ASSERT_TRUE(Verify(cond));
// no signatures; the preimage will get encoded as a fulfillment because it's cheaper
// and the secp256k1 node will get encoded as a condition
cond->threshold = 1;
ASSERT_FALSE(Verify(cond));
// here the signature is set wrong
cond->threshold = 2;
ASSERT_TRUE(Verify(cond));
memset(cond->subconditions[1]->signature, 0, 32);
ASSERT_FALSE(Verify(cond));
}
TEST_F(CCTest, testVerifyEvalCondition)
{
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);
};
// ok
CCFromJson(cond, R"!!({
"type": "threshold-sha-256",
"threshold": 2,
"subfulfillments": [
{ "type": "secp256k1-sha-256", "publicKey": "AgWorQwdvFFfFJrzd5gaq1i4Nq8AjU16shvXb6+AVQtH" },
{ "type": "eval-sha-256", "method": "TestEval", "params": "" }
]})!!");
CC *ecCond = cond->subconditions[1];
ecCond->paramsBin = (unsigned char*) "TestEval";
ecCond->paramsBinLength = 8;
CCSign(mtxTo, cond); // will reorder subconditions
ASSERT_TRUE(Verify(cond));
ecCond->paramsBin = (unsigned char*) "FailEval";
ASSERT_FALSE(Verify(cond));
}
TEST_F(CCTest, testCryptoConditionsDisabled)
{
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);
};
// ok
CCFromJson(cond, R"!!({
"type": "secp256k1-sha-256",
"publicKey": "AgWorQwdvFFfFJrzd5gaq1i4Nq8AjU16shvXb6+AVQtH"
})!!");
CCSign(mtxTo, cond);
ASSERT_TRUE(Verify(cond));
ASSETCHAINS_CC = 0;
ASSERT_FALSE(Verify(cond));
}