shrub/pkg/urcrypt/urcrypt/secp256k1.c
2020-10-10 15:01:31 -07:00

199 lines
5.5 KiB
C

#include "urcrypt.h"
#include "util.h"
#include <string.h>
#include <secp256k1.h>
#include <secp256k1_recovery.h>
#include <secp256k1_preallocated.h>
#define SECP_FLAGS SECP256K1_CONTEXT_VERIFY | SECP256K1_CONTEXT_SIGN
struct urcrypt_secp_context_struct {
secp256k1_context* secp;
uint8_t prealloc[];
};
size_t
urcrypt_secp_prealloc_size()
{
return sizeof(urcrypt_secp_context) +
secp256k1_context_preallocated_size(SECP_FLAGS);
}
int
urcrypt_secp_init(urcrypt_secp_context *context,
uint8_t entropy[32])
{
secp256k1_context* secp =
secp256k1_context_preallocated_create(context->prealloc, SECP_FLAGS);
if ( 1 == secp256k1_context_randomize(secp, entropy) ) {
context->secp = secp;
return 0;
}
else {
secp256k1_context_preallocated_destroy(secp);
return -1;
}
}
void
urcrypt_secp_destroy(urcrypt_secp_context *context)
{
secp256k1_context_preallocated_destroy(context->secp);
}
int
urcrypt_secp_make(uint8_t hash[32], uint8_t key[32], uint8_t out[32])
{
urcrypt__reverse(32, hash);
urcrypt__reverse(32, key);
if ( 1 != secp256k1_nonce_function_rfc6979(
out, // OUT: return arg for nonce
hash, // IN: message / hash */
key, // IN: key32
NULL, // IN: algorithm (NULL == ECDSA)
NULL, // IN: arbitrary data pointer (unused)
0) ) { // IN: attempt number (0 == normal)
return -1;
}
else {
urcrypt__reverse(32, out);
return 0;
}
}
int
urcrypt_secp_sign(urcrypt_secp_context* context,
uint8_t hash[32],
uint8_t key[32],
uint8_t* out_v,
uint8_t out_r[32],
uint8_t out_s[32])
{
secp256k1_ecdsa_recoverable_signature signature;
urcrypt__reverse(32, hash);
urcrypt__reverse(32, key);
/* sign
N.B. if we want the 'v' field we can't use default secp256k1_ecdsa_sign(),
but must use secp256k1_ecdsa_sign_recoverable() */
if ( 1 != secp256k1_ecdsa_sign_recoverable(
context->secp, /* IN: context object */
&signature, /* OUT: signature */
hash, /* IN: 32 byte hash to be signed */
key, /* IN: 32 byte secret key */
NULL, /* IN: nonce-function ptr ; NULL = default */
NULL) ) { /* IN: data for nonce function; not used */
return -1;
}
else {
uint8_t sigbytes[64];
int recid;
if ( 1 != secp256k1_ecdsa_recoverable_signature_serialize_compact(
context->secp, /* IN: context object */
sigbytes, /* OUT: 64 byte sig (r,s) */
&recid, /* OUT: v */
&signature) ) { /* IN: 65 byte sig */
return -2;
}
else {
/* read sigbytes into r and s
convert endianness while we're at it */
uint8_t i, j;
for ( j = 31, i = 0; i < 32; ++i, --j) {
out_r[j] = sigbytes[i];
}
for ( j = 31; i < 64; ++i, --j ) {
out_s[j] = sigbytes[i];
}
*out_v = (uint8_t) recid;
return 0;
}
}
}
int
urcrypt_secp_reco(urcrypt_secp_context* context,
uint8_t hash[32],
uint8_t key_v,
const uint8_t key_r[32],
const uint8_t key_s[32],
uint8_t out_x[32],
uint8_t out_y[32])
{
if ( (NULL == hash) ||
(NULL == key_r) ||
(NULL == key_s) ) {
return -1;
}
else if ( key_v > 3 ) {
return -2;
}
else {
secp256k1_ecdsa_recoverable_signature signature;
uint8_t private[64];
uint8_t i, j;
// make big private key out of two smaller parts, reversing endianness
for ( j = 31, i = 0; i < 32; ++i, --j) {
private[i] = key_r[j];
}
for ( j = 31; i < 64; ++i, --j ) {
private[i] = key_s[j];
}
memset(&signature, 0, sizeof(secp256k1_ecdsa_recoverable_signature));
if ( 1 != secp256k1_ecdsa_recoverable_signature_parse_compact(
context->secp, /* IN: context */
&signature, /* OUT: sig */
private, /* IN: r/s */
key_v) ) { /* IN: v */
return -3;
}
else {
secp256k1_pubkey public;
memset(&public, 0, sizeof(secp256k1_pubkey));
urcrypt__reverse(32, hash);
if ( 1 != secp256k1_ecdsa_recover(
context->secp, /* IN: context */
&public, /* OUT: pub key */
&signature, /* IN: signature */
hash) ) { /* IN: message hash */
return -4;
}
else {
/* convert pub into serialized form that we can get x, y out of */
uint8_t serialized[65];
size_t outputlen = 65;
memset(serialized, 0, outputlen);
if ( 1 != secp256k1_ec_pubkey_serialize(
context->secp, /* IN: context */
serialized, /* OUT: output */
&outputlen, /* IN/OUT: outputlen */
&public, /* IN: pubkey*/
SECP256K1_EC_UNCOMPRESSED) ) { /* IN: flags */
return -5;
}
else {
/* in file
subprojects/secp256k1/src/eckey_impl.h
func
secp256k1_eckey_pubkey_parse()
we can see
byte 0: signal bits (???)
bytes 1-32: x
bytes 33-64: y
convert endianness while we're at it */
for (j = 32, i = 0; i < 32; ++i, --j) {
out_x[i] = serialized[j];
}
for (j = 64, i = 0; i < 32; ++i, --j) {
out_y[i] = serialized[j];
}
return 0;
}
}
}
}
}