Hush Full Node software. We were censored from Github, this is where all development happens now.
https://hush.is
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
351 lines
10 KiB
351 lines
10 KiB
// Copyright (c) 2016-2020 The Hush developers
|
|
/******************************************************************************
|
|
* Copyright © 2014-2019 The SuperNET Developers. *
|
|
* *
|
|
* See the AUTHORS, DEVELOPER-AGREEMENT and LICENSE files at *
|
|
* the top-level directory of this distribution for the individual copyright *
|
|
* holder information and the developer policies on copyright and licensing. *
|
|
* *
|
|
* Unless otherwise agreed in a custom licensing agreement, no part of the *
|
|
* SuperNET software, including this file may be copied, modified, propagated *
|
|
* or distributed except according to the terms contained in the LICENSE file *
|
|
* *
|
|
* Removal or modification of this copyright notice is prohibited. *
|
|
* *
|
|
******************************************************************************/
|
|
|
|
#include "strings.h"
|
|
#include "asn/Condition.h"
|
|
#include "asn/Fulfillment.h"
|
|
#include "asn/OCTET_STRING.h"
|
|
#include "cryptoconditions.h"
|
|
#include "src/internal.h"
|
|
#include "src/threshold.c"
|
|
#include "src/prefix.c"
|
|
#include "src/preimage.c"
|
|
#include "src/ed25519.c"
|
|
#include "src/secp256k1.c"
|
|
#include "src/anon.c"
|
|
#include "src/eval.c"
|
|
#include "src/json_rpc.c"
|
|
#include <cJSON.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
|
|
struct CCType *CCTypeRegistry[] = {
|
|
&CC_PreimageType,
|
|
&CC_PrefixType,
|
|
&CC_ThresholdType,
|
|
NULL, /* &CC_rsaType */
|
|
&CC_Ed25519Type,
|
|
&CC_Secp256k1Type,
|
|
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, /* 6-14 unused */
|
|
&CC_EvalType
|
|
};
|
|
|
|
|
|
int CCTypeRegistryLength = sizeof(CCTypeRegistry) / sizeof(CCTypeRegistry[0]);
|
|
|
|
|
|
void appendUriSubtypes(uint32_t mask, unsigned char *buf) {
|
|
int append = 0;
|
|
for (int i=0; i<32; i++) {
|
|
if (mask & 1 << i) {
|
|
if (append) {
|
|
strcat(buf, ",");
|
|
strcat(buf, CCTypeRegistry[i]->name);
|
|
} else {
|
|
strcat(buf, "&subtypes=");
|
|
strcat(buf, CCTypeRegistry[i]->name);
|
|
append = 1;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
char *cc_conditionUri(const CC *cond) {
|
|
unsigned char *fp = calloc(1, 32);
|
|
cond->type->fingerprint(cond, fp);
|
|
|
|
unsigned char *encoded = base64_encode(fp, 32);
|
|
|
|
unsigned char *out = calloc(1, 1000);
|
|
sprintf(out, "ni:///sha-256;%s?fpt=%s&cost=%lu",encoded, cc_typeName(cond), cc_getCost(cond));
|
|
|
|
if (cond->type->getSubtypes) {
|
|
appendUriSubtypes(cond->type->getSubtypes(cond), out);
|
|
}
|
|
|
|
free(fp);
|
|
free(encoded);
|
|
|
|
return out;
|
|
}
|
|
|
|
|
|
ConditionTypes_t asnSubtypes(uint32_t mask) {
|
|
ConditionTypes_t types;
|
|
uint8_t buf[4] = {0,0,0,0};
|
|
int maxId = 0;
|
|
|
|
for (int i=0; i<32; i++) {
|
|
if (mask & (1<<i)) {
|
|
maxId = i;
|
|
buf[i >> 3] |= 1 << (7 - i % 8);
|
|
}
|
|
}
|
|
|
|
types.size = 1 + (maxId >> 3);
|
|
types.buf = calloc(1, types.size);
|
|
memcpy(types.buf, &buf, types.size);
|
|
types.bits_unused = 7 - maxId % 8;
|
|
return types;
|
|
}
|
|
|
|
|
|
uint32_t fromAsnSubtypes(const ConditionTypes_t types) {
|
|
uint32_t mask = 0;
|
|
for (int i=0; i<types.size*8; i++) {
|
|
if (types.buf[i >> 3] & (1 << (7 - i % 8))) {
|
|
mask |= 1 << i;
|
|
}
|
|
}
|
|
return mask;
|
|
}
|
|
|
|
|
|
size_t cc_conditionBinary(const CC *cond, unsigned char *buf) {
|
|
Condition_t *asn = calloc(1, sizeof(Condition_t));
|
|
asnCondition(cond, asn);
|
|
size_t out = 0;
|
|
asn_enc_rval_t rc = der_encode_to_buffer(&asn_DEF_Condition, asn, buf, 1000);
|
|
if (rc.encoded == -1) goto end;
|
|
out = rc.encoded;
|
|
end:
|
|
ASN_STRUCT_FREE(asn_DEF_Condition, asn);
|
|
return out;
|
|
}
|
|
|
|
|
|
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) {
|
|
fprintf(stderr, "FULFILLMENT NOT ENCODED\n");
|
|
return 0;
|
|
}
|
|
ASN_STRUCT_FREE(asn_DEF_Fulfillment, ffill);
|
|
return rc.encoded;
|
|
}
|
|
|
|
|
|
void asnCondition(const CC *cond, Condition_t *asn) {
|
|
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
|
|
// type. This works out nicely since the union choices have the same binary interface.
|
|
|
|
CompoundSha256Condition_t *choice = &asn->choice.thresholdSha256;
|
|
choice->cost = cc_getCost(cond);
|
|
choice->fingerprint.size = 32;
|
|
choice->fingerprint.buf = calloc(1, 32);
|
|
cond->type->fingerprint(cond, choice->fingerprint.buf);
|
|
choice->subtypes = asnSubtypes(cond->type->getSubtypes(cond));
|
|
}
|
|
|
|
|
|
Condition_t *asnConditionNew(const CC *cond) {
|
|
Condition_t *asn = calloc(1, sizeof(Condition_t));
|
|
asnCondition(cond, asn);
|
|
return asn;
|
|
}
|
|
|
|
|
|
Fulfillment_t *asnFulfillmentNew(const CC *cond) {
|
|
return cond->type->toFulfillment(cond);
|
|
}
|
|
|
|
|
|
unsigned long cc_getCost(const CC *cond) {
|
|
return cond->type->getCost(cond);
|
|
}
|
|
|
|
|
|
CCType *getTypeByAsnEnum(Condition_PR present) {
|
|
for (int i=0; i<CCTypeRegistryLength; i++) {
|
|
if (CCTypeRegistry[i] != NULL && CCTypeRegistry[i]->asnType == present) {
|
|
return CCTypeRegistry[i];
|
|
}
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
|
|
CC *fulfillmentToCC(Fulfillment_t *ffill) {
|
|
CCType *type = getTypeByAsnEnum(ffill->present);
|
|
if (!type) {
|
|
fprintf(stderr, "Unknown fulfillment type: %i\n", ffill->present);
|
|
return 0;
|
|
}
|
|
return type->fromFulfillment(ffill);
|
|
}
|
|
|
|
|
|
CC *cc_readFulfillmentBinary(const unsigned char *ffill_bin, size_t ffill_bin_len) {
|
|
CC *cond = 0;
|
|
unsigned char *buf = calloc(1,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) {
|
|
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;
|
|
}
|
|
|
|
int cc_readFulfillmentBinaryExt(const unsigned char *ffill_bin, size_t ffill_bin_len, CC **ppcc) {
|
|
|
|
int error = 0;
|
|
unsigned char *buf = calloc(1,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) {
|
|
error = rval.code;
|
|
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");
|
|
error = -1;
|
|
goto end;
|
|
}
|
|
if (rc.encoded != ffill_bin_len || 0 != memcmp(ffill_bin, buf, rc.encoded)) {
|
|
error = (rc.encoded == ffill_bin_len) ? -3 : -2;
|
|
goto end;
|
|
}
|
|
|
|
*ppcc = fulfillmentToCC(ffill);
|
|
end:
|
|
free(buf);
|
|
if (ffill) ASN_STRUCT_FREE(asn_DEF_Fulfillment, ffill);
|
|
return error;
|
|
}
|
|
|
|
|
|
int cc_visit(CC *cond, CCVisitor visitor) {
|
|
int out = visitor.visit(cond, visitor);
|
|
if (out && cond->type->visitChildren) {
|
|
out = cond->type->visitChildren(cond, visitor);
|
|
}
|
|
return out;
|
|
}
|
|
|
|
int cc_verify(const struct CC *cond, const unsigned char *msg, size_t msgLength, int doHashMsg,
|
|
const unsigned char *condBin, size_t condBinLength,
|
|
VerifyEval verifyEval, void *evalContext) {
|
|
unsigned char targetBinary[1000];
|
|
//fprintf(stderr,"in cc_verify cond.%p msg.%p[%d] dohash.%d condbin.%p[%d]\n",cond,msg,(int32_t)msgLength,doHashMsg,condBin,(int32_t)condBinLength);
|
|
const size_t binLength = cc_conditionBinary(cond, targetBinary);
|
|
if (0 != memcmp(condBin, targetBinary, binLength)) {
|
|
fprintf(stderr,"cc_verify error A\n");
|
|
return 0;
|
|
}
|
|
if (!cc_ed25519VerifyTree(cond, msg, msgLength)) {
|
|
fprintf(stderr,"cc_verify error B\n");
|
|
return 0;
|
|
}
|
|
|
|
unsigned char msgHash[32];
|
|
if (doHashMsg) sha256(msg, msgLength, msgHash);
|
|
else memcpy(msgHash, msg, 32);
|
|
//int32_t z;
|
|
//for (z=0; z<32; z++)
|
|
// fprintf(stderr,"%02x",msgHash[z]);
|
|
//fprintf(stderr," msgHash msglen.%d\n",(int32_t)msgLength);
|
|
|
|
if (!cc_secp256k1VerifyTreeMsg32(cond, msgHash)) {
|
|
fprintf(stderr," cc_verify error C\n");
|
|
return 0;
|
|
}
|
|
|
|
if (!cc_verifyEval(cond, verifyEval, evalContext)) {
|
|
//fprintf(stderr,"cc_verify error D\n");
|
|
return 0;
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
|
|
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);
|
|
if (rval.code != RC_OK) {
|
|
fprintf(stderr, "Failed reading condition binary\n");
|
|
return NULL;
|
|
}
|
|
CC *cond = mkAnon(asnCond);
|
|
ASN_STRUCT_FREE(asn_DEF_Condition, asnCond);
|
|
return cond;
|
|
}
|
|
|
|
|
|
int cc_isAnon(const CC *cond) {
|
|
return cond->type->typeId == CC_Anon;
|
|
}
|
|
|
|
|
|
enum CCTypeId cc_typeId(const CC *cond) {
|
|
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;
|
|
}
|
|
|
|
|
|
int cc_isFulfilled(const CC *cond) {
|
|
return cond->type->isFulfilled(cond);
|
|
}
|
|
|
|
|
|
char *cc_typeName(const CC *cond) {
|
|
return cc_isAnon(cond) ? cond->conditionType->name : cond->type->name;
|
|
}
|
|
|
|
|
|
CC *cc_new(int typeId) {
|
|
CC *cond = calloc(1, sizeof(CC));
|
|
cond->type = typeId == CC_Anon ? &CC_AnonType : CCTypeRegistry[typeId];
|
|
return cond;
|
|
}
|
|
|
|
|
|
void cc_free(CC *cond) {
|
|
if (cond)
|
|
cond->type->free(cond);
|
|
free(cond);
|
|
}
|
|
|
|
|
|
|