Browse Source

many changes: * fix CC malleability * extra validations for CCs such as requiring a signature and limiting types * different SIGHASH types for CC

pull/4/head
Scott Sadler 6 years ago
parent
commit
563581aff4
  1. 1
      src/Makefile.am
  2. 1
      src/Makefile.zcash.include
  3. 1
      src/cryptoconditions/Makefile.am
  4. 16
      src/cryptoconditions/include/cryptoconditions.h
  5. 15
      src/cryptoconditions/src/anon.c
  6. 68
      src/cryptoconditions/src/cryptoconditions.c
  7. 3
      src/cryptoconditions/src/ed25519.c
  8. 3
      src/cryptoconditions/src/eval.c
  9. 5
      src/cryptoconditions/src/internal.h
  10. 5
      src/cryptoconditions/src/prefix.c
  11. 3
      src/cryptoconditions/src/preimage.c
  12. 3
      src/cryptoconditions/src/secp256k1.c
  13. 51
      src/cryptoconditions/src/threshold.c
  14. 1
      src/cryptoconditions/src/utils.c
  15. 13
      src/cryptoconditions/tests/test_failure_modes.py
  16. 44
      src/komodo_cc.cpp
  17. 33
      src/komodo_cc.h
  18. 45
      src/script/interpreter.cpp
  19. 12
      src/script/interpreter.h
  20. 5
      src/script/script.cpp
  21. 1
      src/zcash/CreateJoinSplit.cpp

1
src/Makefile.am

@ -381,6 +381,7 @@ libbitcoin_common_a_SOURCES = \
hash.cpp \
key.cpp \
keystore.cpp \
komodo_cc.cpp \
netbase.cpp \
primitives/block.cpp \
primitives/transaction.cpp \

1
src/Makefile.zcash.include

@ -28,3 +28,4 @@ zcash_CreateJoinSplit_LDADD = \
$(LIBZCASH_LIBS) \
$(LIBCRYPTOCONDITIONS) \
$(LIBSECP256K1)

1
src/cryptoconditions/Makefile.am

@ -21,6 +21,7 @@ CRYPTOCONDITIONS_CORE=libcryptoconditions_core.la
libcryptoconditions_core_la_SOURCES = \
src/cryptoconditions.c \
src/utils.c \
src/include/cJSON.c \
src/include/sha256.c \
src/include/ed25519/src/keypair.c \

16
src/cryptoconditions/include/cryptoconditions.h

@ -16,6 +16,7 @@ struct CCType;
enum CCTypeId {
CC_Condition = -1,
CC_Preimage = 0,
CC_Prefix = 1,
CC_Threshold = 2,
@ -31,19 +32,27 @@ enum CCTypeId {
typedef int (*VerifyEval)(struct CC *cond, void *context);
/*
* Crypto Condition
*/
typedef struct CC {
struct CCType *type;
union {
// public key types
struct { unsigned char *publicKey, *signature; };
// preimage
struct { unsigned char *preimage; size_t preimageLength; };
// threshold
struct { long threshold; int size; struct CC **subconditions; };
// prefix
struct { unsigned char *prefix; size_t prefixLength; struct CC *subcondition;
unsigned long maxMessageLength; };
// eval
struct { char method[64]; unsigned char *paramsBin; size_t paramsBinLength; };
struct { unsigned char fingerprint[32]; uint32_t subtypes; unsigned long cost; };
// anon
struct { unsigned char fingerprint[32]; uint32_t subtypes; unsigned long cost;
struct CCType *conditionType; };
};
} CC;
@ -76,14 +85,15 @@ size_t cc_fulfillmentBinary(const CC *cond, unsigned char *buf, size_t
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_readConditionBinary(unsigned char *cond_bin, size_t cond_bin_len);
struct CC* cc_readFulfillmentBinary(unsigned char *ffill_bin, size_t ffill_bin_len);
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_typeName(const CC *cond);
uint32_t cc_typeMask(const CC *cond);
void cc_free(struct CC *cond);

15
src/cryptoconditions/src/anon.c

@ -11,22 +11,19 @@ struct CCType cc_anonType;
static CC *mkAnon(const Condition_t *asnCond) {
CCType *realType = getTypeByAsnEnum(asnCond->present);
if (!realType) {
printf("Unknown ASN type: %i", asnCond->present);
return 0;
}
CC *cond = calloc(1, sizeof(CC));
cond->type = (CCType*) calloc(1, sizeof(CCType));
*cond->type = cc_anonType;
strcpy(cond->type->name, realType->name);
cond->type->hasSubtypes = realType->hasSubtypes;
cond->type->typeId = realType->typeId;
cond->type->asnType = realType->asnType;
cond->type = &cc_anonType;
cond->conditionType = realType;
const CompoundSha256Condition_t *deets = &asnCond->choice.thresholdSha256;
memcpy(cond->fingerprint, deets->fingerprint.buf, 32);
cond->cost = deets->cost;
if (realType->hasSubtypes) {
if (realType->getSubtypes) {
cond->subtypes = fromAsnSubtypes(deets->subtypes);
}
return cond;
@ -66,8 +63,6 @@ static Fulfillment_t *anonFulfillment(const CC *cond) {
static void anonFree(CC *cond) {
free(cond->type);
free(cond);
}
@ -76,4 +71,4 @@ static int anonIsFulfilled(const CC *cond) {
}
struct CCType cc_anonType = { -1, "anon (a buffer large enough to accomodate any type name)", Condition_PR_NOTHING, 0, NULL, &anonFingerprint, &anonCost, &anonSubtypes, NULL, &anonToJSON, NULL, &anonFulfillment, &anonIsFulfilled, &anonFree };
struct CCType cc_anonType = { -1, "(anon)", Condition_PR_NOTHING, NULL, &anonFingerprint, &anonCost, &anonSubtypes, NULL, &anonToJSON, NULL, &anonFulfillment, &anonIsFulfilled, &anonFree };

68
src/cryptoconditions/src/cryptoconditions.c

@ -12,7 +12,6 @@
#include "src/anon.c"
#include "src/eval.c"
#include "src/json_rpc.c"
#include "src/utils.c"
#include <cJSON.h>
#include <malloc.h>
@ -57,9 +56,9 @@ unsigned char *cc_conditionUri(const CC *cond) {
unsigned char *out = calloc(1, 1000);
sprintf(out, "ni:///sha-256;%s?fpt=%s&cost=%lu",
encoded, cond->type->name, cc_getCost(cond));
encoded, cc_typeName(cond), cc_getCost(cond));
if (cond->type->hasSubtypes) {
if (cond->type->getSubtypes) {
appendUriSubtypes(cond->type->getSubtypes(cond), out);
}
@ -70,15 +69,6 @@ unsigned char *cc_conditionUri(const CC *cond) {
}
uint32_t cc_typeMask(const CC *cond) {
uint32_t mask = 1 << cond->type->typeId;
if (cond->type->hasSubtypes) {
mask |= cond->type->getSubtypes(cond);
}
return mask;
}
static ConditionTypes_t asnSubtypes(uint32_t mask) {
ConditionTypes_t types;
uint8_t buf[4] = {0,0,0,0};
@ -115,7 +105,7 @@ size_t cc_conditionBinary(const CC *cond, unsigned char *buf) {
asnCondition(cond, asn);
asn_enc_rval_t rc = der_encode_to_buffer(&asn_DEF_Condition, asn, buf, 1000);
if (rc.encoded == -1) {
printf("CONDITION NOT ENCODED\n");
fprintf(stderr, "CONDITION NOT ENCODED\n");
return 0;
}
ASN_STRUCT_FREE(asn_DEF_Condition, asn);
@ -127,7 +117,7 @@ size_t cc_fulfillmentBinary(const CC *cond, unsigned char *buf, size_t length) {
Fulfillment_t *ffill = asnFulfillmentNew(cond);
asn_enc_rval_t rc = der_encode_to_buffer(&asn_DEF_Fulfillment, ffill, buf, length);
if (rc.encoded == -1) {
printf("FULFILLMENT NOT ENCODED\n");
fprintf(stderr, "FULFILLMENT NOT ENCODED\n");
return 0;
}
ASN_STRUCT_FREE(asn_DEF_Fulfillment, ffill);
@ -136,7 +126,7 @@ size_t cc_fulfillmentBinary(const CC *cond, unsigned char *buf, size_t length) {
static void asnCondition(const CC *cond, Condition_t *asn) {
asn->present = cond->type->asnType;
asn->present = cc_isAnon(cond) ? cond->conditionType->asnType : cond->type->asnType;
// This may look a little weird - we dont have a reference here to the correct
// union choice for the condition type, so we just assign everything to the threshold
@ -187,14 +177,28 @@ static CC *fulfillmentToCC(Fulfillment_t *ffill) {
}
CC *cc_readFulfillmentBinary(unsigned char *ffill_bin, size_t ffill_bin_len) {
Fulfillment_t *ffill = 0;
CC *cc_readFulfillmentBinary(const unsigned char *ffill_bin, size_t ffill_bin_len) {
CC *cond = 0;
unsigned char *buf = malloc(ffill_bin_len);
Fulfillment_t *ffill = 0;
asn_dec_rval_t rval = ber_decode(0, &asn_DEF_Fulfillment, (void **)&ffill, ffill_bin, ffill_bin_len);
if (rval.code == RC_OK) {
cond = fulfillmentToCC(ffill);
ASN_STRUCT_FREE(asn_DEF_Fulfillment, ffill);
if (rval.code != RC_OK) {
goto end;
}
// Do malleability check
asn_enc_rval_t rc = der_encode_to_buffer(&asn_DEF_Fulfillment, ffill, buf, ffill_bin_len);
if (rc.encoded == -1) {
fprintf(stderr, "FULFILLMENT NOT ENCODED\n");
goto end;
}
if (rc.encoded != ffill_bin_len || 0 != memcmp(ffill_bin, buf, rc.encoded)) {
goto end;
}
cond = fulfillmentToCC(ffill);
end:
free(buf);
if (ffill) ASN_STRUCT_FREE(asn_DEF_Fulfillment, ffill);
return cond;
}
@ -224,6 +228,7 @@ int cc_verify(const struct CC *cond, const unsigned char *msg, size_t msgLength,
unsigned char msgHash[32];
if (doHashMsg) sha256(msg, msgLength, msgHash);
else memcpy(msgHash, msg, 32);
if (!cc_secp256k1VerifyTreeMsg32(cond, msgHash)) {
return 0;
}
@ -235,7 +240,7 @@ int cc_verify(const struct CC *cond, const unsigned char *msg, size_t msgLength,
}
CC *cc_readConditionBinary(unsigned char *cond_bin, size_t length) {
CC *cc_readConditionBinary(const unsigned char *cond_bin, size_t length) {
Condition_t *asnCond = 0;
asn_dec_rval_t rval;
rval = ber_decode(0, &asn_DEF_Condition, (void **)&asnCond, cond_bin, length);
@ -249,8 +254,21 @@ CC *cc_readConditionBinary(unsigned char *cond_bin, size_t length) {
}
int cc_isAnon(const CC *cond) {
return cond->type->typeId == CC_Condition;
}
enum CCTypeId cc_typeId(const CC *cond) {
return cond->type->typeId;
return cc_isAnon(cond) ? cond->conditionType->typeId : cond->type->typeId;
}
uint32_t cc_typeMask(const CC *cond) {
uint32_t mask = 1 << cc_typeId(cond);
if (cond->type->getSubtypes)
mask |= cond->type->getSubtypes(cond);
return mask;
}
@ -259,9 +277,15 @@ int cc_isFulfilled(const CC *cond) {
}
char *cc_typeName(const CC *cond) {
return cc_isAnon(cond) ? cond->conditionType->name : cond->type->name;
}
void cc_free(CC *cond) {
if (cond)
cond->type->free(cond);
free(cond);
}

3
src/cryptoconditions/src/ed25519.c

@ -158,7 +158,6 @@ static void ed25519Free(CC *cond) {
if (cond->signature) {
free(cond->signature);
}
free(cond);
}
@ -167,4 +166,4 @@ static uint32_t ed25519Subtypes(const CC *cond) {
}
struct CCType cc_ed25519Type = { 4, "ed25519-sha-256", Condition_PR_ed25519Sha256, 0, 0, &ed25519Fingerprint, &ed25519Cost, &ed25519Subtypes, &ed25519FromJSON, &ed25519ToJSON, &ed25519FromFulfillment, &ed25519ToFulfillment, &ed25519IsFulfilled, &ed25519Free };
struct CCType cc_ed25519Type = { 4, "ed25519-sha-256", Condition_PR_ed25519Sha256, 0, &ed25519Fingerprint, &ed25519Cost, &ed25519Subtypes, &ed25519FromJSON, &ed25519ToJSON, &ed25519FromFulfillment, &ed25519ToFulfillment, &ed25519IsFulfilled, &ed25519Free };

3
src/cryptoconditions/src/eval.c

@ -98,7 +98,6 @@ int evalIsFulfilled(const CC *cond) {
static void evalFree(CC *cond) {
free(cond->paramsBin);
free(cond);
}
@ -139,4 +138,4 @@ int cc_verifyEval(const CC *cond, VerifyEval verify, void *context) {
}
struct CCType cc_evalType = { 15, "eval-sha-256", Condition_PR_evalSha256, 0, 0, &evalFingerprint, &evalCost, &evalSubtypes, &evalFromJSON, &evalToJSON, &evalFromFulfillment, &evalToFulfillment, &evalIsFulfilled, &evalFree };
struct CCType cc_evalType = { 15, "eval-sha-256", Condition_PR_evalSha256, 0, &evalFingerprint, &evalCost, &evalSubtypes, &evalFromJSON, &evalToJSON, &evalFromFulfillment, &evalToFulfillment, &evalIsFulfilled, &evalFree };

5
src/cryptoconditions/src/internal.h

@ -1,3 +1,5 @@
#include <Condition.h>
#include <Fulfillment.h>
#include "include/cJSON.h"
#include "asn/asn_application.h"
#include "cryptoconditions.h"
@ -17,10 +19,9 @@ extern "C" {
/*
* Condition Type */
typedef struct CCType {
uint8_t typeId;
int typeId;
unsigned char name[100];
Condition_PR asnType;
int hasSubtypes;
int (*visitChildren)(CC *cond, CCVisitor visitor);
unsigned char *(*fingerprint)(const CC *cond);
unsigned long (*getCost)(const CC *cond);

5
src/cryptoconditions/src/prefix.c

@ -71,7 +71,7 @@ static Fulfillment_t *prefixToFulfillment(const CC *cond) {
static uint32_t prefixSubtypes(const CC *cond) {
return cc_typeMask(cond->subcondition) & ~(1 << cc_prefixType.typeId);
return cc_typeMask(cond->subcondition) & ~(1 << CC_Prefix);
}
@ -119,8 +119,7 @@ int prefixIsFulfilled(const CC *cond) {
static void prefixFree(CC *cond) {
free(cond->prefix);
cc_free(cond->subcondition);
free(cond);
}
struct CCType cc_prefixType = { 1, "prefix-sha-256", Condition_PR_prefixSha256, 1, &prefixVisitChildren, &prefixFingerprint, &prefixCost, &prefixSubtypes, &prefixFromJSON, &prefixToJSON, &prefixFromFulfillment, &prefixToFulfillment, &prefixIsFulfilled, &prefixFree };
struct CCType cc_prefixType = { 1, "prefix-sha-256", Condition_PR_prefixSha256, &prefixVisitChildren, &prefixFingerprint, &prefixCost, &prefixSubtypes, &prefixFromJSON, &prefixToJSON, &prefixFromFulfillment, &prefixToFulfillment, &prefixIsFulfilled, &prefixFree };

3
src/cryptoconditions/src/preimage.c

@ -71,7 +71,6 @@ int preimageIsFulfilled(const CC *cond) {
static void preimageFree(CC *cond) {
free(cond->preimage);
free(cond);
}
@ -80,4 +79,4 @@ static uint32_t preimageSubtypes(const CC *cond) {
}
struct CCType cc_preimageType = { 0, "preimage-sha-256", Condition_PR_preimageSha256, 0, 0, &preimageFingerprint, &preimageCost, &preimageSubtypes, &preimageFromJSON, &preimageToJSON, &preimageFromFulfillment, &preimageToFulfillment, &preimageIsFulfilled, &preimageFree };
struct CCType cc_preimageType = { 0, "preimage-sha-256", Condition_PR_preimageSha256, 0, &preimageFingerprint, &preimageCost, &preimageSubtypes, &preimageFromJSON, &preimageToJSON, &preimageFromFulfillment, &preimageToFulfillment, &preimageIsFulfilled, &preimageFree };

3
src/cryptoconditions/src/secp256k1.c

@ -270,7 +270,6 @@ static void secp256k1Free(CC *cond) {
if (cond->signature) {
free(cond->signature);
}
free(cond);
}
@ -279,4 +278,4 @@ static uint32_t secp256k1Subtypes(const CC *cond) {
}
struct CCType cc_secp256k1Type = { 5, "secp256k1-sha-256", Condition_PR_secp256k1Sha256, 0, 0, &secp256k1Fingerprint, &secp256k1Cost, &secp256k1Subtypes, &secp256k1FromJSON, &secp256k1ToJSON, &secp256k1FromFulfillment, &secp256k1ToFulfillment, &secp256k1IsFulfilled, &secp256k1Free };
struct CCType cc_secp256k1Type = { 5, "secp256k1-sha-256", Condition_PR_secp256k1Sha256, 0, &secp256k1Fingerprint, &secp256k1Cost, &secp256k1Subtypes, &secp256k1FromJSON, &secp256k1ToJSON, &secp256k1FromFulfillment, &secp256k1ToFulfillment, &secp256k1IsFulfilled, &secp256k1Free };

51
src/cryptoconditions/src/threshold.c

@ -16,7 +16,7 @@ static uint32_t thresholdSubtypes(const CC *cond) {
for (int i=0; i<cond->size; i++) {
mask |= cc_typeMask(cond->subconditions[i]);
}
mask &= ~(1 << cc_thresholdType.typeId);
mask &= ~(1 << CC_Threshold);
return mask;
}
@ -53,13 +53,19 @@ static int thresholdVisitChildren(CC *cond, CCVisitor visitor) {
}
static int cmpConditions(const void *a, const void *b) {
static int cmpConditionBin(const void *a, const void *b) {
/* Compare conditions by their ASN binary representation */
unsigned char bufa[BUF_SIZE], bufb[BUF_SIZE];
asn_enc_rval_t r0 = der_encode_to_buffer(&asn_DEF_Condition, *(Condition_t**)a, bufa, BUF_SIZE);
asn_enc_rval_t r1 = der_encode_to_buffer(&asn_DEF_Condition, *(Condition_t**)b, bufb, BUF_SIZE);
int diff = r0.encoded - r1.encoded;
return diff != 0 ? diff : strcmp(bufa, bufb);
// below copied from ASN lib
size_t commonLen = r0.encoded < r1.encoded ? r0.encoded : r1.encoded;
int ret = memcmp(bufa, bufb, commonLen);
if (ret == 0)
return r0.encoded < r1.encoded ? -1 : 1;
return 0;
}
@ -68,13 +74,32 @@ static unsigned char *thresholdFingerprint(const CC *cond) {
ThresholdFingerprintContents_t *fp = calloc(1, sizeof(ThresholdFingerprintContents_t));
fp->threshold = cond->threshold;
for (int i=0; i<cond->size; i++) {
asn_set_add(&fp->subconditions2, asnConditionNew(cond->subconditions[i]));
Condition_t *asnCond = asnConditionNew(cond->subconditions[i]);
asn_set_add(&fp->subconditions2, asnCond);
}
qsort(fp->subconditions2.list.array, cond->size, sizeof(Condition_t*), cmpConditions);
qsort(fp->subconditions2.list.array, cond->size, sizeof(Condition_t*), cmpConditionBin);
return hashFingerprintContents(&asn_DEF_ThresholdFingerprintContents, fp);
}
static int cmpConditionCost(const void *a, const void *b) {
CC *ca = *((CC**)a);
CC *cb = *((CC**)b);
int out = cc_getCost(ca) - cc_getCost(cb);
if (out != 0) return out;
// Do an additional sort to establish consistent order
// between conditions with the same cost.
Condition_t *asna = asnConditionNew(ca);
Condition_t *asnb = asnConditionNew(cb);
out = cmpConditionBin(&asna, &asnb);
ASN_STRUCT_FREE(asn_DEF_Condition, asna);
ASN_STRUCT_FREE(asn_DEF_Condition, asnb);
return out;
}
static CC *thresholdFromFulfillment(const Fulfillment_t *ffill) {
ThresholdFulfillment_t *t = ffill->choice.thresholdSha256;
int threshold = t->subfulfillments.list.count;
@ -83,7 +108,7 @@ static CC *thresholdFromFulfillment(const Fulfillment_t *ffill) {
CC **subconditions = calloc(size, sizeof(CC*));
for (int i=0; i<size; i++) {
subconditions[i] = (i < threshold) ?
subconditions[i] = (i < threshold) ?
fulfillmentToCC(t->subfulfillments.list.array[i]) :
mkAnon(t->subconditions.list.array[i-threshold]);
@ -103,16 +128,11 @@ static CC *thresholdFromFulfillment(const Fulfillment_t *ffill) {
}
static int cmpByCostDesc(const void *c1, const void *c2) {
return cc_getCost(*((CC**)c1)) - cc_getCost(*((CC**)c2));
}
static Fulfillment_t *thresholdToFulfillment(const CC *cond) {
CC *sub;
Fulfillment_t *fulfillment;
qsort(cond->subconditions, cond->size, sizeof(CC*), cmpByCostDesc);
qsort(cond->subconditions, cond->size, sizeof(CC*), cmpConditionCost);
ThresholdFulfillment_t *tf = calloc(1, sizeof(ThresholdFulfillment_t));
@ -124,7 +144,7 @@ static Fulfillment_t *thresholdToFulfillment(const CC *cond) {
asn_set_add(&tf->subfulfillments, fulfillment);
needed--;
} else {
asn_set_add(&tf->subconditions, asnConditionNew(cond->subconditions[i]));
asn_set_add(&tf->subconditions, asnConditionNew(sub));
}
}
@ -199,8 +219,7 @@ static void thresholdFree(CC *cond) {
cc_free(cond->subconditions[i]);
}
free(cond->subconditions);
free(cond);
}
struct CCType cc_thresholdType = { 2, "threshold-sha-256", Condition_PR_thresholdSha256, 1, &thresholdVisitChildren, &thresholdFingerprint, &thresholdCost, &thresholdSubtypes, &thresholdFromJSON, &thresholdToJSON, &thresholdFromFulfillment, &thresholdToFulfillment, &thresholdIsFulfilled, &thresholdFree };
struct CCType cc_thresholdType = { 2, "threshold-sha-256", Condition_PR_thresholdSha256, &thresholdVisitChildren, &thresholdFingerprint, &thresholdCost, &thresholdSubtypes, &thresholdFromJSON, &thresholdToJSON, &thresholdFromFulfillment, &thresholdToFulfillment, &thresholdIsFulfilled, &thresholdFree };

1
src/cryptoconditions/src/utils.c

@ -187,6 +187,7 @@ int jsonGetBase64Optional(const cJSON *params, unsigned char *key, unsigned char
return checkDecodeBase64(item, key, err, data, size);
}
void jsonAddBase64(cJSON *params, unsigned char *key, unsigned char *bin, size_t size) {
unsigned char *b64 = base64_encode(bin, size);
cJSON_AddItemToObject(params, key, cJSON_CreateString(b64));

13
src/cryptoconditions/tests/test_failure_modes.py

@ -1,7 +1,7 @@
import json
import ctypes
import base64
from .test_vectors import jsonRPC, so, decode_base64 as d64
from .test_vectors import jsonRPC, so, decode_base64 as d64, encode_base64 as e64
'''
@ -10,7 +10,6 @@ These tests are aimed at edge cases of serverside deployment.
As such, the main functions to test are decoding and verifying fulfillment payloads.
'''
cc_rfb = lambda f: so.cc_readFulfillmentBinary(f, len(f))
cc_rcb = lambda f: so.cc_readConditionBinary(f, len(f))
@ -44,7 +43,7 @@ def test_large_fulfillment():
def test_decode_valid_condition():
# Valid preimage
assert cc_rcb(d64('oCWAIMqXgRLKG73K-sIxs5oj3E2nhu_4FHxOcrmAd4Wv7ki7gQEB'))
assert cc_rcb(d64(b'oCWAIMqXgRLKG73K-sIxs5oj3E2nhu_4FHxOcrmAd4Wv7ki7gQEB'))
# Somewhat bogus condition (prefix with no subtypes) but nonetheless valid structure
assert cc_rcb(unhex("a10a8001618101ff82020700"))
@ -76,3 +75,11 @@ def test_non_canonical_secp256k1():
'message': ''
})
assert res['valid'] == False
def test_malleability_checked():
assert cc_rfb(b'\xa2\x13\xa0\x0f\xa0\x05\x80\x03abc\xa0\x06\x80\x04abcd\xa1\x00')
assert not cc_rfb(b'\xa2\x13\xa0\x0f\xa0\x06\x80\x04abcd\xa0\x05\x80\x03abc\xa1\x00')
so.cc_conditionUri.restype = ctypes.c_char_p

44
src/komodo_cc.cpp

@ -0,0 +1,44 @@
#include "cryptoconditions/include/cryptoconditions.h"
#include "komodo_cc.h"
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)
{
int mask = cc_typeMask(cond);
if (mask & ~CCEnabledTypes) return false;
// Also require that the condition have at least one signable node
if (!(mask & CCSigningNodes)) return false;
return true;
}
bool IsSignedCryptoCondition(const CC *cond)
{
if (!cc_isFulfilled(cond)) return false;
if (1 << cc_typeId(cond) & CCSigningNodes) return true;
if (cc_typeId(cond) == CC_Threshold)
for (int i=0; i<cond->size; i++)
if (IsSignedCryptoCondition(cond->subconditions[i])) return true;
return false;
}

33
src/komodo_cc.h

@ -2,39 +2,22 @@
#define KOMODO_CC_H
#include "cryptoconditions/include/cryptoconditions.h"
#include "primitives/transaction.h"
/*
* Check if CryptoConditions is enabled based on chain or cmd flag
*/
extern int32_t ASSETCHAINS_CC;
static bool IsCryptoConditionsEnabled()
{
return 0 != ASSETCHAINS_CC;
}
bool IsCryptoConditionsEnabled();
/*
* Check if the server can accept the condition based on it's structure / types
*/
static bool IsAcceptableCryptoCondition(const CC *cond)
{
int32_t typeMask = cc_typeMask(cond);
// Require a signature to prevent transaction malleability
if (0 == typeMask & (1 << CC_Secp256k1) ||
0 == typeMask & (1 << CC_Ed25519)) return false;
// 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 enabledTypes = 1 << CC_Secp256k1 | 1 << CC_Threshold | 1 << CC_Eval | \
1 << CC_Preimage | 1 << CC_Ed25519;
if (typeMask & ~enabledTypes) return false;
return true;
}
bool IsSupportedCryptoCondition(const CC *cond);
/*
* Check if crypto condition is signed. Can only accept signed conditions.
*/
bool IsSignedCryptoCondition(const CC *cond);
#endif /* KOMODO_CC_H */

45
src/script/interpreter.cpp

@ -950,27 +950,19 @@ bool EvalScript(
if (stack.size() < 2)
return set_error(serror, SCRIPT_ERR_INVALID_STACK_OPERATION);
valtype& vchFulfillment = stacktop(-2);
valtype& vchCondition = stacktop(-1);
CC *cond = cc_readFulfillmentBinary((unsigned char*)vchFulfillment.data(),
vchFulfillment.size());
if (!cond) {
int fResult = checker.CheckCryptoCondition(stacktop(-1), stacktop(-2), script, consensusBranchId);
if (fResult == -1) {
return set_error(serror, SCRIPT_ERR_CRYPTOCONDITION_INVALID_FULFILLMENT);
}
bool fSuccess = checker.CheckCryptoCondition(cond, vchCondition, script, consensusBranchId);
cc_free(cond);
popstack(stack);
popstack(stack);
stack.push_back(fSuccess ? vchTrue : vchFalse);
stack.push_back(fResult == 1 ? vchTrue : vchFalse);
if (opcode == OP_CHECKCRYPTOCONDITIONVERIFY)
{
if (fSuccess)
if (fResult == 1)
popstack(stack);
else
return set_error(serror, SCRIPT_ERR_CRYPTOCONDITION_VERIFY);
@ -1295,18 +1287,33 @@ bool TransactionSignatureChecker::CheckSig(
}
bool TransactionSignatureChecker::CheckCryptoCondition(const CC *cond, const std::vector<unsigned char>& condBin, const CScript& scriptCode, uint32_t consensusBranchId) const
int TransactionSignatureChecker::CheckCryptoCondition(
const std::vector<unsigned char>& condBin,
const std::vector<unsigned char>& ffillBin,
const CScript& scriptCode,
uint32_t consensusBranchId) const
{
if (!IsAcceptableCryptoCondition(cond)) return false;
// Hash type is one byte tacked on to the end of the fulfillment
if (ffillBin.empty())
return false;
CC *cond = cc_readFulfillmentBinary((unsigned char*)ffillBin.data(), ffillBin.size()-1);
if (!cond) return -1;
if (!IsSupportedCryptoCondition(cond)) return 0;
if (!IsSignedCryptoCondition(cond)) return 0;
uint256 sighash;
int nHashType = ffillBin.back();
try {
sighash = SignatureHash(scriptCode, *txTo, nIn, SIGHASH_ALL, amount, consensusBranchId, this->txdata);
sighash = SignatureHash(scriptCode, *txTo, nIn, nHashType, amount, consensusBranchId, this->txdata);
} catch (logic_error ex) {
return false;
return 0;
}
return cc_verify(cond, (const unsigned char*)&sighash, 32, 0,
condBin.data(), condBin.size(), GetCCEval(), (void*)this);
int out = cc_verify(cond, (const unsigned char*)&sighash, 32, 0,
condBin.data(), condBin.size(), GetCCEval(), (void*)this);
cc_free(cond);
return out;
}

12
src/script/interpreter.h

@ -128,7 +128,11 @@ public:
return false;
}
virtual bool CheckCryptoCondition(const CC *cond, const std::vector<unsigned char>& condBin, const CScript& scriptCode, uint32_t consensusBranchId) const
virtual int CheckCryptoCondition(
const std::vector<unsigned char>& condBin,
const std::vector<unsigned char>& ffillBin,
const CScript& scriptCode,
uint32_t consensusBranchId) const
{
return false;
}
@ -152,7 +156,11 @@ public:
TransactionSignatureChecker(const CTransaction* txToIn, unsigned int nInIn, const CAmount& amountIn, const PrecomputedTransactionData& txdataIn) : txTo(txToIn), nIn(nInIn), amount(amountIn), txdata(&txdataIn) {}
bool CheckSig(const std::vector<unsigned char>& scriptSig, const std::vector<unsigned char>& vchPubKey, const CScript& scriptCode, uint32_t consensusBranchId) const;
bool CheckLockTime(const CScriptNum& nLockTime) const;
bool CheckCryptoCondition(const CC *cond, const std::vector<unsigned char>& condBin, const CScript& scriptCode, uint32_t consensusBranchId) const;
int CheckCryptoCondition(
const std::vector<unsigned char>& condBin,
const std::vector<unsigned char>& ffillBin,
const CScript& scriptCode,
uint32_t consensusBranchId) const;
VerifyEval GetCCEval() const;
};

5
src/script/script.cpp

@ -250,8 +250,9 @@ bool CScript::MayAcceptCryptoCondition() const
if (!(opcode > OP_0 && opcode < OP_PUSHDATA1)) return false;
CC *cond = cc_readConditionBinary(data.data(), data.size());
if (!cond) return false;
bool accept = IsAcceptableCryptoCondition(cond);
return accept;
bool out = IsSupportedCryptoCondition(cond);
cc_free(cond);
return out;
}
bool CScript::IsPushOnly() const

1
src/zcash/CreateJoinSplit.cpp

@ -11,6 +11,7 @@
char ASSETCHAINS_SYMBOL[KOMODO_ASSETCHAIN_MAXLEN];
int64_t MAX_MONEY = 200000000 * 100000000LL;
uint16_t BITCOIND_PORT = 7771;
uint32_t ASSETCHAINS_CC = 0;
using namespace libzcash;

Loading…
Cancel
Save