// 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. * * * ******************************************************************************/ #define _GNU_SOURCE 1 #if __linux #include #elif defined(_WIN32) || defined(_WIN64) #include #endif #include #include #include "asn/Condition.h" #include "asn/Fulfillment.h" #include "asn/Secp256k1Fulfillment.h" #include "asn/Secp256k1FingerprintContents.h" #include "asn/OCTET_STRING.h" #include "include/cJSON.h" #include "include/secp256k1/include/secp256k1.h" #include "cryptoconditions.h" #include "internal.h" struct CCType CC_Secp256k1Type; static const size_t SECP256K1_PK_SIZE = 33; static const size_t SECP256K1_SK_SIZE = 32; static const size_t SECP256K1_SIG_SIZE = 64; secp256k1_context *ec_ctx_sign = 0, *ec_ctx_verify = 0; pthread_mutex_t cc_secp256k1ContextLock = PTHREAD_MUTEX_INITIALIZER; void lockSign() { pthread_mutex_lock(&cc_secp256k1ContextLock); if (!ec_ctx_sign) { ec_ctx_sign = secp256k1_context_create(SECP256K1_CONTEXT_SIGN); } unsigned char ent[32]; #ifdef SYS_getrandom int read = syscall(SYS_getrandom, ent, 32, 0); #else FILE *fp = fopen("/dev/urandom", "r"); int read = (int) fread(&ent, 1, 32, fp); fclose(fp); #endif if (read != 32) { int32_t i; for (i=0; i<32; i++) ((uint8_t *)ent)[i] = rand(); } if (!secp256k1_context_randomize(ec_ctx_sign, ent)) { fprintf(stderr, "Could not randomize secp256k1 context\n"); exit(-1); } } void unlockSign() { pthread_mutex_unlock(&cc_secp256k1ContextLock); } void initVerify() { if (!ec_ctx_verify) { pthread_mutex_lock(&cc_secp256k1ContextLock); if (!ec_ctx_verify) ec_ctx_verify = secp256k1_context_create(SECP256K1_CONTEXT_VERIFY); pthread_mutex_unlock(&cc_secp256k1ContextLock); } } static void secp256k1Fingerprint(const CC *cond, uint8_t *out) { Secp256k1FingerprintContents_t *fp = calloc(1, sizeof(Secp256k1FingerprintContents_t)); OCTET_STRING_fromBuf(&fp->publicKey, cond->publicKey, SECP256K1_PK_SIZE); hashFingerprintContents(&asn_DEF_Secp256k1FingerprintContents, fp, out); } int secp256k1Verify(CC *cond, CCVisitor visitor) { if (cond->type->typeId != CC_Secp256k1Type.typeId) return 1; initVerify(); int rc; // parse pubkey secp256k1_pubkey pk; rc = secp256k1_ec_pubkey_parse(ec_ctx_verify, &pk, cond->publicKey, SECP256K1_PK_SIZE); if (rc != 1) return 0; // parse siganature secp256k1_ecdsa_signature sig; rc = secp256k1_ecdsa_signature_parse_compact(ec_ctx_verify, &sig, cond->signature); if (rc != 1) return 0; // Only accepts lower S signatures rc = secp256k1_ecdsa_verify(ec_ctx_verify, &sig, visitor.msg, &pk); if (rc != 1) return 0; return 1; } int cc_secp256k1VerifyTreeMsg32(const CC *cond, const unsigned char *msg32) { int subtypes = cc_typeMask(cond); if (subtypes & (1 << CC_PrefixType.typeId) && subtypes & (1 << CC_Secp256k1Type.typeId)) { // No support for prefix currently, due to pending protocol decision on // how to combine message and prefix into 32 byte hash return 0; } CCVisitor visitor = {&secp256k1Verify, msg32, 0, NULL}; int out = cc_visit(cond, visitor); return out; } /* * Signing data */ typedef struct CCSecp256k1SigningData { const unsigned char *pk; const unsigned char *sk; int nSigned; } 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_Secp256k1) return 1; CCSecp256k1SigningData *signing = (CCSecp256k1SigningData*) visitor.context; if (0 != memcmp(cond->publicKey, signing->pk, SECP256K1_PK_SIZE)) return 1; secp256k1_ecdsa_signature sig; lockSign(); int rc = secp256k1_ecdsa_sign(ec_ctx_sign, &sig, visitor.msg, signing->sk, NULL, NULL); unlockSign(); if (rc != 1) { fprintf(stderr,"secp256k1Sign rc.%d\n",rc); return 0; } if (!cond->signature) cond->signature = calloc(1, SECP256K1_SIG_SIZE); secp256k1_ecdsa_signature_serialize_compact(ec_ctx_verify, cond->signature, &sig); signing->nSigned++; return 1; } /* * 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_Prefix)) { // No support for prefix currently, due to pending protocol decision on // how to combine message and prefix into 32 byte hash return 0; } // derive the pubkey secp256k1_pubkey spk; lockSign(); int rc = secp256k1_ec_pubkey_create(ec_ctx_sign, &spk, privateKey); unlockSign(); if (rc != 1) { fprintf(stderr, "Cryptoconditions couldn't derive secp256k1 pubkey\n"); return 0; } // serialize pubkey //unsigned char *publicKey = calloc(1, SECP256K1_PK_SIZE); unsigned char publicKey[SECP256K1_PK_SIZE]; size_t ol = SECP256K1_PK_SIZE; secp256k1_ec_pubkey_serialize(ec_ctx_verify, publicKey, &ol, &spk, SECP256K1_EC_COMPRESSED); { int32_t z; for (z=0; z<33; z++) fprintf(stderr,"%02x",publicKey[z]); fprintf(stderr," pubkey\n"); } // sign CCSecp256k1SigningData signing = {publicKey, privateKey, 0}; CCVisitor visitor = {&secp256k1Sign, msg32, 32, &signing}; cc_visit(cond, visitor); //free(publicKey); return signing.nSigned; } static unsigned long secp256k1Cost(const CC *cond) { return 131072; } static CC *cc_secp256k1Condition(const unsigned char *publicKey, const unsigned char *signature) { // Check that pk parses initVerify(); secp256k1_pubkey spk; int rc = secp256k1_ec_pubkey_parse(ec_ctx_verify, &spk, publicKey, SECP256K1_PK_SIZE); if (!rc) { return NULL; } unsigned char *pk = 0, *sig = 0; pk = calloc(1, SECP256K1_PK_SIZE); memcpy(pk, publicKey, SECP256K1_PK_SIZE); if (signature) { sig = calloc(1, SECP256K1_SIG_SIZE); memcpy(sig, signature, SECP256K1_SIG_SIZE); } CC *cond = cc_new(CC_Secp256k1); cond->publicKey = pk; cond->signature = sig; return cond; } static CC *secp256k1FromJSON(const cJSON *params, char *err) { CC *cond = 0; unsigned char *pk = 0, *sig = 0; size_t pkSize, sigSize; if (!jsonGetHex(params, "publicKey", err, &pk, &pkSize)) goto END; if (!jsonGetHexOptional(params, "signature", err, &sig, &sigSize)) goto END; if (sig && SECP256K1_SIG_SIZE != sigSize) { strcpy(err, "signature has incorrect length"); goto END; } cond = cc_secp256k1Condition(pk, sig); if (!cond) { strcpy(err, "invalid public key"); } END: free(pk); free(sig); return cond; } static void secp256k1ToJSON(const CC *cond, cJSON *params) { jsonAddHex(params, "publicKey", cond->publicKey, SECP256K1_PK_SIZE); if (cond->signature) { jsonAddHex(params, "signature", cond->signature, SECP256K1_SIG_SIZE); } } static CC *secp256k1FromFulfillment(const Fulfillment_t *ffill) { return cc_secp256k1Condition(ffill->choice.secp256k1Sha256.publicKey.buf, ffill->choice.secp256k1Sha256.signature.buf); } static Fulfillment_t *secp256k1ToFulfillment(const CC *cond) { if (!cond->signature) { return NULL; } Fulfillment_t *ffill = calloc(1, sizeof(Fulfillment_t)); ffill->present = Fulfillment_PR_secp256k1Sha256; Secp256k1Fulfillment_t *sec = &ffill->choice.secp256k1Sha256; OCTET_STRING_fromBuf(&sec->publicKey, cond->publicKey, SECP256K1_PK_SIZE); OCTET_STRING_fromBuf(&sec->signature, cond->signature, SECP256K1_SIG_SIZE); return ffill; } int secp256k1IsFulfilled(const CC *cond) { return cond->signature > 0; } static void secp256k1Free(CC *cond) { free(cond->publicKey); if (cond->signature) { free(cond->signature); } } static uint32_t secp256k1Subtypes(const CC *cond) { return 0; } struct CCType CC_Secp256k1Type = { 5, "secp256k1-sha-256", Condition_PR_secp256k1Sha256, 0, &secp256k1Fingerprint, &secp256k1Cost, &secp256k1Subtypes, &secp256k1FromJSON, &secp256k1ToJSON, &secp256k1FromFulfillment, &secp256k1ToFulfillment, &secp256k1IsFulfilled, &secp256k1Free };