diff options
Diffstat (limited to 'vere/pkg/noun/jets/e/secp.c')
-rw-r--r-- | vere/pkg/noun/jets/e/secp.c | 298 |
1 files changed, 298 insertions, 0 deletions
diff --git a/vere/pkg/noun/jets/e/secp.c b/vere/pkg/noun/jets/e/secp.c new file mode 100644 index 0000000..fa0fbd2 --- /dev/null +++ b/vere/pkg/noun/jets/e/secp.c @@ -0,0 +1,298 @@ +/// @file + +#include "jets/q.h" +#include "jets/w.h" + +#include "noun.h" +#include "urcrypt.h" +#include "ent/ent.h" + +static urcrypt_secp_context* sec_u; + +/* call at process start */ +void +u3je_secp_init() +{ + c3_y ent_y[32]; + ent_getentropy(ent_y, 32); + sec_u = malloc(urcrypt_secp_prealloc_size()); + + if ( 0 != urcrypt_secp_init(sec_u, ent_y) ) { + u3l_log("u3e_secp_init failed"); + abort(); + } +} + +/* call at process end */ +void +u3je_secp_stop() +{ + urcrypt_secp_destroy(sec_u); + free(sec_u); + sec_u = NULL; +} + +/* util funcs + */ +static c3_t +_cqes_in_order(u3_atom a) +{ + // this is the "n" parameter of the secp256k1 curve + static const c3_w now_w[8] = { + 0xd0364141, 0xbfd25e8c, 0xaf48a03b, 0xbaaedce6, + 0xfffffffe, 0xffffffff, 0xffffffff, 0xffffffff + }; + + if ( 0 == a ) { + return 0; + } + else if ( c3y == u3a_is_cat(a) ) { + return 1; + } + else { + u3a_atom* a_u = u3a_to_ptr(a); + c3_w len_w = a_u->len_w; + + if ( len_w < 8 ) { + return 1; + } + else if ( len_w > 8 ) { + return 0; + } + else { + c3_y i_y; + c3_w *buf_w = a_u->buf_w; + // loop from most to least significant words + for ( i_y = 8; i_y > 0; ) { + c3_w b_w = buf_w[i_y], + o_w = now_w[--i_y]; + if ( b_w < o_w ) { + return 1; + } + else if ( b_w > o_w ) { + return 0; + } + } + return 1; + } + } +} + +static void +_cqes_unpack_fe(u3_atom k, c3_y out_y[32]) +{ + if ( _cqes_in_order(k) ) { + u3r_bytes(0, 32, out_y, k); + } + else { + u3m_bail(c3__exit); + } +} + +/* sign hash with priv key + */ +static u3_noun +_cqes_sign(u3_atom has, + u3_atom prv) +{ + c3_y has_y[32]; + + if ( 0 != u3r_bytes_fit(32, has_y, has) ) { + return u3m_bail(c3__exit); + } + else { + c3_y prv_y[32], v_y, r_y[32], s_y[32]; + _cqes_unpack_fe(prv, prv_y); + + return( 0 == urcrypt_secp_sign(sec_u, has_y, prv_y, &v_y, r_y, s_y) ) + ? u3nt(v_y, u3i_bytes(32, r_y), u3i_bytes(32, s_y)) + : u3_none; + } +} + +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))) { + return u3m_bail(c3__exit); + } + else { + return u3l_punt("secp-sign", _cqes_sign(has, prv)); + } +} + +/* recover pubkey from signature (which is how we verify signatures) +*/ +static u3_noun +_cqes_reco(u3_atom has, + u3_atom siv, /* signature: v */ + u3_atom sir, /* signature: r */ + u3_atom sis) /* signature: s */ +{ + c3_y has_y[32]; + if ( !((siv < 4) && (0 == u3r_bytes_fit(32, has_y, has)) ) ) { + return u3m_bail(c3__exit); + } + else { + c3_y sir_y[32], sis_y[32], x_y[32], y_y[32]; + _cqes_unpack_fe(sir, sir_y); + _cqes_unpack_fe(sis, sis_y); + return + ( 0 == urcrypt_secp_reco(sec_u, has_y, siv, sir_y, sis_y, x_y, y_y) ) + ? u3nc(u3i_bytes(32, x_y), u3i_bytes(32, y_y)) + : u3_none; + } +} + +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)) ) { + return u3m_bail(c3__exit); + } + else { + return u3l_punt("secp-reco", _cqes_reco(has, siv, sir, sis)); + } +} + +static u3_atom +_cqes_make(u3_atom has, + u3_atom prv) +{ + c3_y has_y[32]; + + if ( 0 != u3r_bytes_fit(32, has_y, has) ) { + return u3m_bail(c3__exit); + } + else { + c3_y prv_y[32], out_y[32]; + _cqes_unpack_fe(prv, prv_y); + return ( 0 == urcrypt_secp_make(has_y, prv_y, out_y) ) + ? u3i_bytes(32, out_y) + : u3_none; + } +} + +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)) ) { + return u3m_bail(c3__exit); + } + else { + return u3l_punt("secp-make", _cqes_make(has, prv)); + } +} + +/* create a schnorr signature +*/ +static u3_weak +_cqes_sosi(u3_atom sk, u3_atom m, u3_atom a) +{ + c3_y key_y[32]; + c3_y mes_y[32]; + c3_y aux_y[32]; + + if ( (0 != u3r_bytes_fit(32, key_y, sk)) || + (0 != u3r_bytes_fit(32, mes_y, m)) || + (0 != u3r_bytes_fit(32, aux_y, a)) ) + { + return u3m_bail(c3__exit); + } + else { + c3_y sig_y[64]; + + return + ( 0 == urcrypt_secp_schnorr_sign(sec_u, key_y, mes_y, aux_y, sig_y) ) + ? u3i_bytes(64, sig_y) + : u3_none; + } +} + +u3_noun +u3we_sosi(u3_noun cor) +{ + u3_noun key, mes, aux; + + if ( (c3n == u3r_mean(cor, + u3x_sam_2, &key, + u3x_sam_6, &mes, + u3x_sam_7, &aux, + 0)) || + (c3n == u3ud(key)) || + (c3n == u3ud(mes)) || + (c3n == u3ud(aux)) ) + { + return u3m_bail(c3__exit); + } + else { + return u3l_punt("secp-sosi", _cqes_sosi(key, mes, aux)); + } +} + +/* verify a schnorr signature +*/ +static u3_atom +_cqes_sove(u3_atom pk, u3_atom m, u3_atom sig) +{ + c3_y pub_y[32]; + c3_y mes_y[32]; + c3_y sig_y[64]; + + if ( (0 != u3r_bytes_fit(32, pub_y, pk)) || + (0 != u3r_bytes_fit(32, mes_y, m)) || + (0 != u3r_bytes_fit(64, sig_y, sig)) ) + { + return u3m_bail(c3__exit); + } + else { + return __(urcrypt_secp_schnorr_veri(sec_u, sig_y, mes_y, pub_y)); + } +} + +u3_noun +u3we_sove(u3_noun cor) +{ + u3_noun pub, mes, sig; + + if ( (c3n == u3r_mean(cor, + u3x_sam_2, &pub, + u3x_sam_6, &mes, + u3x_sam_7, &sig, + 0)) || + (c3n == u3ud(pub)) || + (c3n == u3ud(mes)) || + (c3n == u3ud(sig)) ) + { + return u3m_bail(c3__exit); + } + else { + return _cqes_sove(pub, mes, sig); + } +} |