quickjs-tart

quickjs-based runtime for wallet-core logic
Log | Files | Refs | README | LICENSE

commit c57beff4c4df73311fb9be9790097685af84d2c3
parent 8f7e8963934ad99b2d85d5044cc9ece3c15e5169
Author: Florian Dold <florian@dold.me>
Date:   Tue, 13 Dec 2022 14:42:14 +0100

kx operations

Diffstat:
Mquickjs-libc.c | 135+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++----------
1 file changed, 119 insertions(+), 16 deletions(-)

diff --git a/quickjs-libc.c b/quickjs-libc.c @@ -4246,6 +4246,27 @@ exception: goto done; } +uint8_t *expect_fixed_buffer(JSContext *ctx, + JSValue val, size_t len, + const char *msg) +{ + uint8_t *buf; + size_t sz; + + buf = JS_GetArrayBuffer(ctx, &sz, val); + if (!buf) { + return NULL; + } + if (sz != len) { + JS_ThrowTypeError(ctx, "invalid length for %s", msg); + return NULL; + } + return buf; +} + +#define REQUIRE(cond, _label) do { if (!(cond)) { goto _label; } } while (0) + + static JSValue make_js_ta_copy(JSContext *ctx, uint8_t *data, size_t size) { JSValue array_buf; @@ -4276,19 +4297,15 @@ static JSValue js_talercrypto_hash(JSContext *ctx, JSValue this_val, static JSValue js_talercrypto_eddsa_key_get_public(JSContext *ctx, JSValue this_val, int argc, JSValueConst *argv) { - size_t size; uint8_t *buf; unsigned char pk[crypto_sign_PUBLICKEYBYTES]; unsigned char sk[crypto_sign_SECRETKEYBYTES]; - buf = JS_GetArrayBuffer(ctx, &size, argv[0]); - + buf = expect_fixed_buffer(ctx, argv[0], 32, "eddsa private key"); + if (!buf) { return JS_EXCEPTION; } - if (size != 32) { - return JS_ThrowTypeError(ctx, "invalid private key size"); - } crypto_sign_seed_keypair(pk, sk, buf); // FIXME: clean up stack! @@ -4296,6 +4313,26 @@ static JSValue js_talercrypto_eddsa_key_get_public(JSContext *ctx, JSValue this_ return make_js_ta_copy(ctx, pk, crypto_sign_PUBLICKEYBYTES); } +static JSValue js_talercrypto_ecdhe_key_get_public(JSContext *ctx, JSValue this_val, + int argc, JSValueConst *argv) +{ + uint8_t *buf; + unsigned char pk[crypto_scalarmult_BYTES]; + + buf = expect_fixed_buffer(ctx, argv[0], 32, "ecdh private key"); + + if (!buf) { + return JS_EXCEPTION; + } + + if (0 != crypto_scalarmult_base(pk, buf)) { + return JS_EXCEPTION; + } + // FIXME: clean up stack! + + return make_js_ta_copy(ctx, pk, crypto_sign_PUBLICKEYBYTES); +} + /** * (msg, priv) => sig */ @@ -4460,16 +4497,76 @@ exception: goto done; } -//static JSValue js_talercrypto_kx_ecdhe_eddsa(JSContext *ctx, JSValue this_val, -// int argc, JSValueConst *argv) -//{ -//} -// -//static JSValue js_talercrypto_kx_eddsa_ecdhe(JSContext *ctx, JSValue this_val, -// int argc, JSValueConst *argv) -//{ -//} -// +/** + * (ecdhePriv, eddsaPub) -> keyMaterial + */ +static JSValue js_talercrypto_kx_ecdh_eddsa(JSContext *ctx, JSValue this_val, + int argc, JSValueConst *argv) +{ + JSValue ret_val; + uint8_t p[crypto_scalarmult_BYTES]; + uint8_t *ecdh_priv; + uint8_t *eddsa_pub; + uint8_t curve25510_pk[crypto_scalarmult_BYTES]; + uint8_t key_material[crypto_hash_BYTES]; + + ecdh_priv = expect_fixed_buffer(ctx, argv[0], 32, "ecdhe priv"); + REQUIRE(ecdh_priv, exception); + + eddsa_pub = expect_fixed_buffer(ctx, argv[1], 32, "eddsa pub"); + REQUIRE(eddsa_pub, exception); + + if (0 != crypto_sign_ed25519_pk_to_curve25519(curve25510_pk, eddsa_pub)) { + goto exception; + } + if (0 != crypto_scalarmult(p, ecdh_priv, curve25510_pk)) { + goto exception; + } + if (0 != crypto_hash(key_material, p, 32)) { + JS_ThrowTypeError(ctx, "hashing failed"); + goto exception; + } + ret_val = make_js_ta_copy(ctx, key_material, crypto_hash_BYTES); +done: + return ret_val; +exception: + ret_val = JS_EXCEPTION; + goto done; +} + +/** + * (eddsaPriv, ecdhePub) -> keyMaterial + */ +static JSValue js_talercrypto_kx_eddsa_ecdh(JSContext *ctx, JSValue this_val, + int argc, JSValueConst *argv) +{ + JSValue ret_val; + uint8_t *priv; + uint8_t *pub; + uint8_t hc[crypto_hash_BYTES]; + uint8_t a[crypto_scalarmult_SCALARBYTES]; + uint8_t p[crypto_scalarmult_BYTES]; + uint8_t key_material[crypto_hash_BYTES]; + + priv = expect_fixed_buffer(ctx, argv[0], 32, "eddsa priv"); + REQUIRE(priv, exception); + pub = expect_fixed_buffer(ctx, argv[1], 32, "ecdh pub"); + REQUIRE(pub, exception); + + crypto_hash(hc, priv, 32); + memcpy (a, &hc, 32); + if (0 != crypto_scalarmult(p, a, pub)) { + goto exception; + } + crypto_hash(key_material, p, crypto_scalarmult_BYTES); + ret_val = make_js_ta_copy(ctx, key_material, crypto_hash_BYTES); +done: + return ret_val; +exception: + ret_val = JS_EXCEPTION; + goto done; +} + static JSValue js_decode_utf8(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv) @@ -4512,12 +4609,18 @@ void js_std_add_helpers(JSContext *ctx, int argc, char **argv) JS_NewCFunction(ctx, js_talercrypto_hash, "_hash", 1)); JS_SetPropertyStr(ctx, global_obj, "_eddsaGetPublic", JS_NewCFunction(ctx, js_talercrypto_eddsa_key_get_public, "_eddsaGetPublic", 1)); + JS_SetPropertyStr(ctx, global_obj, "_ecdheGetPublic", + JS_NewCFunction(ctx, js_talercrypto_ecdhe_key_get_public, "_ecdheGetPublic", 1)); JS_SetPropertyStr(ctx, global_obj, "_eddsaSign", JS_NewCFunction(ctx, js_talercrypto_eddsa_sign, "_eddsaSign", 2)); JS_SetPropertyStr(ctx, global_obj, "_eddsaVerify", JS_NewCFunction(ctx, js_talercrypto_eddsa_verify, "_eddsaVerify", 3)); JS_SetPropertyStr(ctx, global_obj, "_kdf", JS_NewCFunction(ctx, js_talercrypto_kdf, "_kdf", 4)); + JS_SetPropertyStr(ctx, global_obj, "_keyExchangeEddsaEcdh", + JS_NewCFunction(ctx, js_talercrypto_kx_eddsa_ecdh, "_keyExchangeEddsaEcdh", 2)); + JS_SetPropertyStr(ctx, global_obj, "_keyExchangeEcdhEddsa", + JS_NewCFunction(ctx, js_talercrypto_kx_ecdh_eddsa, "_keyExchangeEcdhEddsa", 2)); /* same methods as the mozilla JS shell */ if (argc >= 0) {