shrub/jets/e/secp.c
2018-09-04 18:17:52 +02:00

316 lines
9.4 KiB
C

/* j/5/secp.c
**
*/
#include "all.h"
#include "../include/secp256k1.h"
#include "../include/secp256k1_recovery.h"
/* util funcs
*/
/* no guarantees if 'in' and 'out' overlap / are the same */
static void byte_reverse(c3_y *i_y, /* in */
c3_y *o_y, /* out */
c3_w n_w) /* size */
{
c3_w j_w;
for (j_w = 0; j_w < n_w; j_w++){
o_y[n_w - 1 - j_w] = i_y[j_w];
}
return;
}
/* Identical to u3r_bytes, but reverses bytes in place.
could be cleaner if we modified u3r_bytes(), but not gonna do that.
This func exists bc Urbit code base is explicitly little-endian,
and secp256k1 library is explicitly big-endian.
Several times below we do the pattern of (1) invoke u3r_bytes, (2) invert. Do it in a func.
*/
static void u3r_bytes_reverse(c3_w a_w,
c3_w b_w,
c3_y* c_y, /* out */
u3_atom d) /* in */
{
u3r_bytes(a_w, b_w, c_y, d);
c3_w i_w;
for (i_w = 0; i_w < ((b_w - a_w) / 2) ; i_w++) {
c3_y lo = c_y[i_w];
c3_y hi = c_y[b_w - i_w - 1];
c_y[i_w] = hi;
c_y[b_w - i_w - 1] = lo;
}
return;
}
/* sign hash with priv key
*/
u3_noun
u3we_sign(u3_noun cor)
{
u3_noun has, prv;
if ( (c3n == u3r_mean(cor,
u3x_sam_2, &has,
u3x_sam_3, &prv,
0)) ||
(c3n == u3ud(has)) ||
(c3n == u3ud(prv))) {
fprintf(stderr, "\rsecp jet: crypto package error\n");
return u3m_bail(c3__exit);
} else {
return (u3qe_sign(has, prv));
}
}
u3_noun
u3qe_sign(u3_atom has,
u3_atom prv)
{
/* build library context object once (and only once) */
static secp256k1_context * ctx_u = NULL;
if (NULL == ctx_u) {
ctx_u = secp256k1_context_create(SECP256K1_CONTEXT_SIGN);
}
/* parse arguments, convert endianness */
c3_y has_y[32]; /* hash */
c3_y prv_y[32]; /* private key */
u3r_bytes_reverse(0, 32, has_y, has);
u3r_bytes_reverse(0, 32, prv_y, prv);
/* sign
N.B. if we want the 'v' field we can't use default secp256k1_ecdsa_sign(),
but must use secp256k1_ecdsa_sign_recoverable() */
c3_ws ret;
secp256k1_ecdsa_recoverable_signature sig_u;
ret = secp256k1_ecdsa_sign_recoverable(ctx_u, /* IN: context object */
& sig_u, /* OUT: signature */
(const c3_y *) has_y, /* IN: 32 byte hash to be signed */
(const c3_y *) prv_y, /* IN: 32 byte secret key */
(secp256k1_nonce_function) NULL, /* IN: nonce-function ptr ; NULL = default */
(const void *) NULL); /* IN: data for nonce function; not used */
if (1 != ret) {
fprintf(stderr, "\rsecp jet: crypto package error\n");
return u3m_bail(c3__exit);
}
/* convert opaque 65 byte signature into v + [r + s]
convert endianness while we're at it */
c3_y rec_y[64];
c3_ws v = 0;
ret = secp256k1_ecdsa_recoverable_signature_serialize_compact(ctx_u,
rec_y, /* OUT: 64 byte sig (r,s) */
& v, /* OUT: v */
& sig_u); /* IN: 65 byte sig */
if (1 != ret) {
fprintf(stderr, "\rsecp jet: crypto package error\n");
return u3m_bail(c3__exit);
}
c3_y s_y[32];
c3_y r_y[32];
byte_reverse(rec_y, r_y, 32);
byte_reverse(rec_y + 32, s_y, 32);
/* package s,r,v signature for return */
u3_noun s = u3i_words(8, (const c3_w*) s_y);
u3_noun r = u3i_words(8, (const c3_w*) r_y);
return (u3nt(v, r, s));
}
/* recover pubkey from signature (which is how we verify signatures)
*/
u3_noun
u3we_reco(u3_noun cor)
{
u3_noun has, /* hash */
siv, sir, sis; /* signature: v, r, s */
if ( (c3n == u3r_mean(cor,
u3x_sam_2, &has,
u3x_sam_6, &siv,
u3x_sam_14, &sir,
u3x_sam_15, &sis,
0)) ||
(c3n == u3ud(has)) ||
(c3n == u3ud(siv)) ||
(c3n == u3ud(sir)) ||
(c3n == u3ud(sis)) )
{
fprintf(stderr, "\rsecp jet: crypto package error\n");
return u3m_bail(c3__exit);
} else {
return u3qe_reco(has, siv, sir, sis);
}
}
u3_noun
u3qe_reco(u3_atom has,
u3_atom siv, /* signature: v */
u3_atom sir, /* signature: r */
u3_atom sis) /* signature: s */
{
/* build library context object once (and only once) */
static secp256k1_context * ctx_u = NULL;
if (NULL == ctx_u) {
ctx_u = secp256k1_context_create(SECP256K1_CONTEXT_VERIFY);
}
/* parse arguments, convert endianness */
c3_y has_y[32];
c3_y sir_y[32];
c3_y sis_y[32];
c3_y siv_y[1];
u3r_bytes_reverse(0, 32, has_y, has);
u3r_bytes_reverse(0, 32, sir_y, sir);
u3r_bytes_reverse(0, 32, sis_y, sis);
u3r_bytes_reverse(0, 1, siv_y, siv);
/* build the signature object */
c3_y ras_y[64]; /* priv key: r and s components */
c3_ws i_ws;
for (i_ws = 0; i_ws < 32; i_ws++) {
ras_y[i_ws] = sir_y[i_ws] ;
}
for (i_ws = 0; i_ws < 32; i_ws++) {
ras_y[i_ws + 32] = sis_y[i_ws] ;
}
c3_ws siv_ws = siv_y[0];
secp256k1_ecdsa_recoverable_signature sig_u;
memset( (void *) & sig_u, 0, sizeof(secp256k1_ecdsa_recoverable_signature) );
c3_ws ret = secp256k1_ecdsa_recoverable_signature_parse_compact(ctx_u, /* IN: context */
& sig_u, /* OUT: sig */
ras_y, /* IN: r/s */
siv_ws); /* IN: v */
if (1 != ret) {
fprintf(stderr, "\rsecp jet: crypto package error\n");
return u3m_bail(c3__exit);
}
/* turn sign into puk_u */
secp256k1_pubkey puk_u;
memset((void *) & puk_u, 0, sizeof(secp256k1_pubkey) );
ret = secp256k1_ecdsa_recover(ctx_u, /* IN: context */
& puk_u, /* OUT: pub key */
& sig_u, /* IN: signature */
(const c3_y *) & has); /* IN: message has */
if (1 != ret) {
fprintf(stderr, "\rsecp jet: crypto package error\n");
return u3m_bail(c3__exit);
}
/* convert puk_u into serialized form that we can get x,y out of */
c3_y puk_y[65];
size_t outputlen = 65;
memset((void *) puk_y, 0, 65);
ret = secp256k1_ec_pubkey_serialize( ctx_u, /* IN: */
puk_y, /* OUT: */
& outputlen, /* OUT: */
& puk_u, /* IN: */
SECP256K1_EC_UNCOMPRESSED); /* IN: flags */
if (1 != ret) {
fprintf(stderr, "\rsecp jet: crypto package error\n");
return u3m_bail(c3__exit);
}
/* in file
subprojects/secp256k1/src/eckey_impl.h
func
secp256k1_eckey_puk_u_parse()
we can see
byte 0: signal bits (???)
bytes 1-32: x
bytes 33-64: y
convert endianness while we're at it */
c3_y x_y[32];
for (i_ws = 0; i_ws < 32; i_ws++) {
x_y[i_ws] = puk_y[32 - i_ws];
}
u3_noun x = u3i_bytes(32, x_y);
c3_y y_y[32];
for (i_ws = 0; i_ws < 32; i_ws++) {
y_y[i_ws] = puk_y[64 - i_ws];
}
u3_noun y = u3i_bytes(32, y_y);
/* returns x,y */
return(u3nc(x, y));
}
u3_noun
u3we_make(u3_noun cor)
{
u3_noun has, prv;
if ( (c3n == u3r_mean(cor,
u3x_sam_2, &has,
u3x_sam_3, &prv,
0)) ||
(c3n == u3ud(has)) ||
(c3n == u3ud(prv)) )
{
fprintf(stderr, "\rsecp jet: crypto package error\n");
return u3m_bail(c3__exit);
} else {
return u3qe_make(has, prv);
}
}
u3_noun
u3qe_make(u3_atom has,
u3_atom prv)
{
c3_y hel_y[32]; /* hash, little endian */
c3_y heb_y[32]; /* hash, big endian */
u3r_bytes(0, 32, hel_y, has);
byte_reverse(hel_y, heb_y, 32);
c3_y pel_y[32]; /* priv key, little endian */
c3_y peb_y[32]; /* priv key, big endian */
u3r_bytes(0, 32, pel_y, prv);
byte_reverse(pel_y, peb_y, 32);
c3_ws ret_ws;
c3_y neb_y[32]; /* nonce */
ret_ws = secp256k1_nonce_function_rfc6979(neb_y, /* OUT: return arg for nonce */
(const c3_y *) heb_y, /* IN: message / hash */
(const c3_y *) peb_y, /* IN: key32 */
NULL, /* IN: algorithm (NULL == ECDSA) */
(void *) NULL, /* IN: arbitrary data pointer (unused) */
0); /* IN: attempt number (0 == normal) */
if (1 != ret_ws) {
fprintf(stderr, "\rsecp jet: crypto package error\n");
return u3m_bail(c3__exit);
}
c3_y nel_y[32];
byte_reverse(neb_y, nel_y, 32);
u3_noun non = u3i_words(8, (const c3_w*) nel_y);
return(non);
}