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.
 
 
 
 
 
 

316 lines
9.3 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. *
* *
******************************************************************************/
#define _GNU_SOURCE 1
#if __linux
#include <sys/syscall.h>
#elif defined(_WIN32) || defined(_WIN64)
#include <windows.h>
#endif
#include <unistd.h>
#include <pthread.h>
#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 };