forked from hush/hush3
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
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 };
|
|
|