bitcoinpqc 0.4.0

Post-Quantum Cryptographic signature algorithms for Bitcoin (BIP-360)
#include <pthread.h>
#include <string.h>

#include <secp256k1.h>
#include <secp256k1_schnorrsig.h>
#include <secp256k1_extrakeys.h>

#include "secp256k1_schnorr.h"

#define SECP256K1_SECRET_KEY_SIZE 32
#define SECP256K1_PUBLIC_KEY_SIZE 32
#define SECP256K1_SIGNATURE_SIZE 64

static secp256k1_context *secp256k1_ctx = NULL;
static pthread_once_t secp256k1_ctx_once = PTHREAD_ONCE_INIT;

static void secp256k1_ctx_init(void) {
    secp256k1_ctx = secp256k1_context_create(
        SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY
    );
}

static int secp256k1_ctx_ensure(void) {
    if (pthread_once(&secp256k1_ctx_once, secp256k1_ctx_init) != 0) {
        return SECP256K1_SCHNORR_ERR_ARG;
    }

    if (secp256k1_ctx == NULL) {
        return SECP256K1_SCHNORR_ERR_ARG;
    }

    return SECP256K1_SCHNORR_OK;
}

int secp256k1_schnorr_keygen(
    uint8_t *pk,
    uint8_t *sk,
    const uint8_t *seed,
    size_t seed_size
) {
    secp256k1_keypair keypair;
    secp256k1_xonly_pubkey xonly_pk;

    if (!pk || !sk || !seed || seed_size < SECP256K1_SECRET_KEY_SIZE) {
        return SECP256K1_SCHNORR_ERR_ARG;
    }

    if (secp256k1_ctx_ensure() != SECP256K1_SCHNORR_OK) {
        return SECP256K1_SCHNORR_ERR_ARG;
    }

    memcpy(sk, seed, SECP256K1_SECRET_KEY_SIZE);

    if (!secp256k1_ec_seckey_verify(secp256k1_ctx, sk)) {
        return SECP256K1_SCHNORR_ERR_KEY;
    }

    if (!secp256k1_keypair_create(secp256k1_ctx, &keypair, sk)) {
        return SECP256K1_SCHNORR_ERR_KEY;
    }

    if (!secp256k1_keypair_xonly_pub(
            secp256k1_ctx,
            &xonly_pk,
            NULL,
            &keypair)) {
        return SECP256K1_SCHNORR_ERR_KEY;
    }

    if (!secp256k1_xonly_pubkey_serialize(secp256k1_ctx, pk, &xonly_pk)) {
        return SECP256K1_SCHNORR_ERR_KEY;
    }

    return SECP256K1_SCHNORR_OK;
}

int secp256k1_schnorr_sign(
    uint8_t *sig,
    size_t *sig_len,
    const uint8_t *sk,
    const uint8_t *msg,
    size_t msg_size
) {
    secp256k1_keypair keypair;
    uint8_t msg32[SECP256K1_SECRET_KEY_SIZE];

    if (!sig || !sig_len || !sk || !msg || msg_size < SECP256K1_SECRET_KEY_SIZE) {
        return SECP256K1_SCHNORR_ERR_ARG;
    }

    if (secp256k1_ctx_ensure() != SECP256K1_SCHNORR_OK) {
        return SECP256K1_SCHNORR_ERR_ARG;
    }

    memcpy(msg32, msg, SECP256K1_SECRET_KEY_SIZE);

    if (!secp256k1_ec_seckey_verify(secp256k1_ctx, sk)) {
        return SECP256K1_SCHNORR_ERR_KEY;
    }

    if (!secp256k1_keypair_create(secp256k1_ctx, &keypair, sk)) {
        return SECP256K1_SCHNORR_ERR_KEY;
    }

    if (!secp256k1_schnorrsig_sign32(secp256k1_ctx, sig, msg32, &keypair, NULL)) {
        return SECP256K1_SCHNORR_ERR_SIG;
    }

    *sig_len = SECP256K1_SIGNATURE_SIZE;
    return SECP256K1_SCHNORR_OK;
}

int secp256k1_schnorr_verify(
    const uint8_t *sig,
    size_t sig_len,
    const uint8_t *msg,
    size_t msg_size,
    const uint8_t *pk
) {
    secp256k1_xonly_pubkey xonly_pk;

    if (!sig || !msg || !pk) {
        return SECP256K1_SCHNORR_ERR_ARG;
    }

    if (sig_len != SECP256K1_SIGNATURE_SIZE ||
        msg_size < SECP256K1_SECRET_KEY_SIZE) {
        return SECP256K1_SCHNORR_ERR_ARG;
    }

    if (secp256k1_ctx_ensure() != SECP256K1_SCHNORR_OK) {
        return SECP256K1_SCHNORR_ERR_ARG;
    }

    if (!secp256k1_xonly_pubkey_parse(secp256k1_ctx, &xonly_pk, pk)) {
        return SECP256K1_SCHNORR_ERR_KEY;
    }

    if (secp256k1_schnorrsig_verify(
            secp256k1_ctx,
            sig,
            msg,
            SECP256K1_SECRET_KEY_SIZE,
            &xonly_pk)) {
        return SECP256K1_SCHNORR_OK;
    }

    return SECP256K1_SCHNORR_ERR_SIG;
}