|
|
|
// Copyright (c) 2013 Pieter Wuille
|
|
|
|
// Distributed under the MIT/X11 software license, see the accompanying
|
|
|
|
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
|
|
|
|
|
|
|
#include "impl/num.h"
|
|
|
|
#include "impl/field.h"
|
|
|
|
#include "impl/group.h"
|
|
|
|
#include "impl/ecmult.h"
|
|
|
|
#include "impl/ecdsa.h"
|
|
|
|
|
|
|
|
#ifdef __cplusplus
|
|
|
|
extern "C" {
|
|
|
|
#endif
|
|
|
|
|
|
|
|
void secp256k1_start(void) {
|
|
|
|
secp256k1_fe_start();
|
|
|
|
secp256k1_ge_start();
|
|
|
|
secp256k1_ecmult_start();
|
|
|
|
}
|
|
|
|
|
|
|
|
void secp256k1_stop(void) {
|
|
|
|
secp256k1_ecmult_stop();
|
|
|
|
secp256k1_ge_stop();
|
|
|
|
secp256k1_fe_stop();
|
|
|
|
}
|
|
|
|
|
|
|
|
int secp256k1_ecdsa_verify(const unsigned char *msg, int msglen, const unsigned char *sig, int siglen, const unsigned char *pubkey, int pubkeylen) {
|
|
|
|
int ret = -3;
|
|
|
|
secp256k1_num_t m;
|
|
|
|
secp256k1_num_init(&m);
|
|
|
|
secp256k1_ecdsa_sig_t s;
|
|
|
|
secp256k1_ecdsa_sig_init(&s);
|
|
|
|
secp256k1_ge_t q;
|
|
|
|
secp256k1_num_set_bin(&m, msg, msglen);
|
|
|
|
|
|
|
|
if (!secp256k1_ecdsa_pubkey_parse(&q, pubkey, pubkeylen)) {
|
|
|
|
ret = -1;
|
|
|
|
goto end;
|
|
|
|
}
|
|
|
|
if (!secp256k1_ecdsa_sig_parse(&s, sig, siglen)) {
|
|
|
|
ret = -2;
|
|
|
|
goto end;
|
|
|
|
}
|
|
|
|
if (!secp256k1_ecdsa_sig_verify(&s, &q, &m)) {
|
|
|
|
ret = 0;
|
|
|
|
goto end;
|
|
|
|
}
|
|
|
|
ret = 1;
|
|
|
|
end:
|
|
|
|
secp256k1_ecdsa_sig_free(&s);
|
|
|
|
secp256k1_num_free(&m);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
int secp256k1_ecdsa_sign(const unsigned char *message, int messagelen, unsigned char *signature, int *signaturelen, const unsigned char *seckey, const unsigned char *nonce) {
|
|
|
|
secp256k1_num_t sec, non, msg;
|
|
|
|
secp256k1_num_init(&sec);
|
|
|
|
secp256k1_num_init(&non);
|
|
|
|
secp256k1_num_init(&msg);
|
|
|
|
secp256k1_num_set_bin(&sec, seckey, 32);
|
|
|
|
secp256k1_num_set_bin(&non, nonce, 32);
|
|
|
|
secp256k1_num_set_bin(&msg, message, messagelen);
|
|
|
|
secp256k1_ecdsa_sig_t sig;
|
|
|
|
secp256k1_ecdsa_sig_init(&sig);
|
|
|
|
int ret = secp256k1_ecdsa_sig_sign(&sig, &sec, &msg, &non, NULL);
|
|
|
|
if (ret) {
|
|
|
|
secp256k1_ecdsa_sig_serialize(signature, signaturelen, &sig);
|
|
|
|
}
|
|
|
|
secp256k1_ecdsa_sig_free(&sig);
|
|
|
|
secp256k1_num_free(&msg);
|
|
|
|
secp256k1_num_free(&non);
|
|
|
|
secp256k1_num_free(&sec);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
int secp256k1_ecdsa_sign_compact(const unsigned char *message, int messagelen, unsigned char *sig64, const unsigned char *seckey, const unsigned char *nonce, int *recid) {
|
|
|
|
secp256k1_num_t sec, non, msg;
|
|
|
|
secp256k1_num_init(&sec);
|
|
|
|
secp256k1_num_init(&non);
|
|
|
|
secp256k1_num_init(&msg);
|
|
|
|
secp256k1_num_set_bin(&sec, seckey, 32);
|
|
|
|
secp256k1_num_set_bin(&non, nonce, 32);
|
|
|
|
secp256k1_num_set_bin(&msg, message, messagelen);
|
|
|
|
secp256k1_ecdsa_sig_t sig;
|
|
|
|
secp256k1_ecdsa_sig_init(&sig);
|
|
|
|
int ret = secp256k1_ecdsa_sig_sign(&sig, &sec, &msg, &non, recid);
|
|
|
|
if (ret) {
|
|
|
|
secp256k1_num_get_bin(sig64, 32, &sig.r);
|
|
|
|
secp256k1_num_get_bin(sig64 + 32, 32, &sig.s);
|
|
|
|
}
|
|
|
|
secp256k1_ecdsa_sig_free(&sig);
|
|
|
|
secp256k1_num_free(&msg);
|
|
|
|
secp256k1_num_free(&non);
|
|
|
|
secp256k1_num_free(&sec);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
int secp256k1_ecdsa_recover_compact(const unsigned char *msg, int msglen, const unsigned char *sig64, unsigned char *pubkey, int *pubkeylen, int compressed, int recid) {
|
|
|
|
int ret = 0;
|
|
|
|
secp256k1_num_t m;
|
|
|
|
secp256k1_num_init(&m);
|
|
|
|
secp256k1_ecdsa_sig_t sig;
|
|
|
|
secp256k1_ecdsa_sig_init(&sig);
|
|
|
|
secp256k1_num_set_bin(&sig.r, sig64, 32);
|
|
|
|
secp256k1_num_set_bin(&sig.s, sig64 + 32, 32);
|
|
|
|
secp256k1_num_set_bin(&m, msg, msglen);
|
|
|
|
|
|
|
|
secp256k1_ge_t q;
|
|
|
|
if (secp256k1_ecdsa_sig_recover(&sig, &q, &m, recid)) {
|
|
|
|
secp256k1_ecdsa_pubkey_serialize(&q, pubkey, pubkeylen, compressed);
|
|
|
|
ret = 1;
|
|
|
|
}
|
|
|
|
secp256k1_ecdsa_sig_free(&sig);
|
|
|
|
secp256k1_num_free(&m);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
int secp256k1_ecdsa_seckey_verify(const unsigned char *seckey) {
|
|
|
|
secp256k1_num_t sec;
|
|
|
|
secp256k1_num_init(&sec);
|
|
|
|
secp256k1_num_set_bin(&sec, seckey, 32);
|
|
|
|
int ret = !secp256k1_num_is_zero(&sec) &&
|
|
|
|
(secp256k1_num_cmp(&sec, &secp256k1_ge_consts->order) < 0);
|
|
|
|
secp256k1_num_free(&sec);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
int secp256k1_ecdsa_pubkey_verify(const unsigned char *pubkey, int pubkeylen) {
|
|
|
|
secp256k1_ge_t q;
|
|
|
|
return secp256k1_ecdsa_pubkey_parse(&q, pubkey, pubkeylen);
|
|
|
|
}
|
|
|
|
|
|
|
|
int secp256k1_ecdsa_pubkey_create(unsigned char *pubkey, int *pubkeylen, const unsigned char *seckey, int compressed) {
|
|
|
|
secp256k1_num_t sec;
|
|
|
|
secp256k1_num_init(&sec);
|
|
|
|
secp256k1_num_set_bin(&sec, seckey, 32);
|
|
|
|
secp256k1_gej_t pj;
|
|
|
|
secp256k1_ecmult_gen(&pj, &sec);
|
|
|
|
secp256k1_ge_t p;
|
|
|
|
secp256k1_ge_set_gej(&p, &pj);
|
|
|
|
secp256k1_ecdsa_pubkey_serialize(&p, pubkey, pubkeylen, compressed);
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
int secp256k1_ecdsa_pubkey_decompress(unsigned char *pubkey, int *pubkeylen) {
|
|
|
|
secp256k1_ge_t p;
|
|
|
|
if (!secp256k1_ecdsa_pubkey_parse(&p, pubkey, *pubkeylen))
|
|
|
|
return 0;
|
|
|
|
secp256k1_ecdsa_pubkey_serialize(&p, pubkey, pubkeylen, 0);
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
int secp256k1_ecdsa_privkey_tweak_add(unsigned char *seckey, const unsigned char *tweak) {
|
|
|
|
int ret = 1;
|
|
|
|
secp256k1_num_t term;
|
|
|
|
secp256k1_num_init(&term);
|
|
|
|
secp256k1_num_set_bin(&term, tweak, 32);
|
|
|
|
if (secp256k1_num_cmp(&term, &secp256k1_ge_consts->order) >= 0)
|
|
|
|
ret = 0;
|
|
|
|
secp256k1_num_t sec;
|
|
|
|
secp256k1_num_init(&sec);
|
|
|
|
if (ret) {
|
|
|
|
secp256k1_num_set_bin(&sec, seckey, 32);
|
|
|
|
secp256k1_num_add(&sec, &sec, &term);
|
|
|
|
secp256k1_num_mod(&sec, &secp256k1_ge_consts->order);
|
|
|
|
if (secp256k1_num_is_zero(&sec))
|
|
|
|
ret = 0;
|
|
|
|
}
|
|
|
|
if (ret)
|
|
|
|
secp256k1_num_get_bin(seckey, 32, &sec);
|
|
|
|
secp256k1_num_free(&sec);
|
|
|
|
secp256k1_num_free(&term);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
int secp256k1_ecdsa_pubkey_tweak_add(unsigned char *pubkey, int pubkeylen, const unsigned char *tweak) {
|
|
|
|
int ret = 1;
|
|
|
|
secp256k1_num_t term;
|
|
|
|
secp256k1_num_init(&term);
|
|
|
|
secp256k1_num_set_bin(&term, tweak, 32);
|
|
|
|
if (secp256k1_num_cmp(&term, &secp256k1_ge_consts->order) >= 0)
|
|
|
|
ret = 0;
|
|
|
|
secp256k1_ge_t p;
|
|
|
|
if (ret) {
|
|
|
|
if (!secp256k1_ecdsa_pubkey_parse(&p, pubkey, pubkeylen))
|
|
|
|
ret = 0;
|
|
|
|
}
|
|
|
|
if (ret) {
|
|
|
|
secp256k1_gej_t pt;
|
|
|
|
secp256k1_ecmult_gen(&pt, &term);
|
|
|
|
secp256k1_gej_add_ge(&pt, &pt, &p);
|
|
|
|
if (secp256k1_gej_is_infinity(&pt))
|
|
|
|
ret = 0;
|
|
|
|
secp256k1_ge_set_gej(&p, &pt);
|
|
|
|
int oldlen = pubkeylen;
|
|
|
|
secp256k1_ecdsa_pubkey_serialize(&p, pubkey, &pubkeylen, oldlen <= 33);
|
|
|
|
assert(pubkeylen == oldlen);
|
|
|
|
}
|
|
|
|
secp256k1_num_free(&term);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
int secp256k1_ecdsa_privkey_tweak_mul(unsigned char *seckey, const unsigned char *tweak) {
|
|
|
|
int ret = 1;
|
|
|
|
secp256k1_num_t factor;
|
|
|
|
secp256k1_num_init(&factor);
|
|
|
|
secp256k1_num_set_bin(&factor, tweak, 32);
|
|
|
|
if (secp256k1_num_is_zero(&factor))
|
|
|
|
ret = 0;
|
|
|
|
if (secp256k1_num_cmp(&factor, &secp256k1_ge_consts->order) >= 0)
|
|
|
|
ret = 0;
|
|
|
|
secp256k1_num_t sec;
|
|
|
|
secp256k1_num_init(&sec);
|
|
|
|
if (ret) {
|
|
|
|
secp256k1_num_set_bin(&sec, seckey, 32);
|
|
|
|
secp256k1_num_mod_mul(&sec, &sec, &factor, &secp256k1_ge_consts->order);
|
|
|
|
}
|
|
|
|
if (ret)
|
|
|
|
secp256k1_num_get_bin(seckey, 32, &sec);
|
|
|
|
secp256k1_num_free(&sec);
|
|
|
|
secp256k1_num_free(&factor);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
int secp256k1_ecdsa_pubkey_tweak_mul(unsigned char *pubkey, int pubkeylen, const unsigned char *tweak) {
|
|
|
|
int ret = 1;
|
|
|
|
secp256k1_num_t factor;
|
|
|
|
secp256k1_num_init(&factor);
|
|
|
|
secp256k1_num_set_bin(&factor, tweak, 32);
|
|
|
|
if (secp256k1_num_is_zero(&factor))
|
|
|
|
ret = 0;
|
|
|
|
if (secp256k1_num_cmp(&factor, &secp256k1_ge_consts->order) >= 0)
|
|
|
|
ret = 0;
|
|
|
|
secp256k1_ge_t p;
|
|
|
|
if (ret) {
|
|
|
|
if (!secp256k1_ecdsa_pubkey_parse(&p, pubkey, pubkeylen))
|
|
|
|
ret = 0;
|
|
|
|
}
|
|
|
|
if (ret) {
|
|
|
|
secp256k1_num_t zero;
|
|
|
|
secp256k1_num_init(&zero);
|
|
|
|
secp256k1_num_set_int(&zero, 0);
|
|
|
|
secp256k1_gej_t pt;
|
|
|
|
secp256k1_gej_set_ge(&pt, &p);
|
|
|
|
secp256k1_ecmult(&pt, &pt, &factor, &zero);
|
|
|
|
secp256k1_num_free(&zero);
|
|
|
|
secp256k1_ge_set_gej(&p, &pt);
|
|
|
|
int oldlen = pubkeylen;
|
|
|
|
secp256k1_ecdsa_pubkey_serialize(&p, pubkey, &pubkeylen, oldlen <= 33);
|
|
|
|
assert(pubkeylen == oldlen);
|
|
|
|
}
|
|
|
|
secp256k1_num_free(&factor);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
int secp256k1_ecdsa_privkey_export(const unsigned char *seckey, unsigned char *privkey, int *privkeylen, int compressed) {
|
|
|
|
secp256k1_num_t key;
|
|
|
|
secp256k1_num_init(&key);
|
|
|
|
secp256k1_num_set_bin(&key, seckey, 32);
|
|
|
|
int ret = secp256k1_ecdsa_privkey_serialize(privkey, privkeylen, &key, compressed);
|
|
|
|
secp256k1_num_free(&key);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
int secp256k1_ecdsa_privkey_import(unsigned char *seckey, const unsigned char *privkey, int privkeylen) {
|
|
|
|
secp256k1_num_t key;
|
|
|
|
secp256k1_num_init(&key);
|
|
|
|
int ret = secp256k1_ecdsa_privkey_parse(&key, privkey, privkeylen);
|
|
|
|
if (ret)
|
|
|
|
secp256k1_num_get_bin(seckey, 32, &key);
|
|
|
|
secp256k1_num_free(&key);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef __cplusplus
|
|
|
|
}
|
|
|
|
#endif
|