quickjs-tart

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

commit 04f223102329fccee543f3e0c5b38f094b8b3a20
parent 1cc287c4a2b0988268490edaae7444ff9ddc758f
Author: Florian Dold <florian@dold.me>
Date:   Fri, 23 Dec 2022 12:53:42 +0100

native hash state and structured clone

Diffstat:
Mtart_module.c | 127+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--
1 file changed, 125 insertions(+), 2 deletions(-)

diff --git a/tart_module.c b/tart_module.c @@ -449,7 +449,7 @@ static JSValue js_talercrypto_hash(JSContext *ctx, JSValue this_val, if (!buf) { return JS_EXCEPTION; } - crypto_hash(h, buf, size); + crypto_hash_sha512(h, buf, size); return make_js_ta_copy(ctx, h, crypto_hash_BYTES); } @@ -1187,13 +1187,132 @@ static JSValue js_decode_utf8(JSContext *ctx, JSValueConst this_val, return JS_NewStringLen(ctx, (char *) utf8_buf, psize); } +static JSValue js_structured_clone(JSContext *ctx, JSValueConst this_val, + int argc, JSValueConst *argv) +{ + uint8_t *buf; + size_t len; + JSValue obj; + + buf = JS_WriteObject(ctx, &len, argv[0], JS_WRITE_OBJ_REFERENCE); + + if (NULL == buf) { + return JS_EXCEPTION; + } + + obj = JS_ReadObject(ctx, buf, len, JS_WRITE_OBJ_REFERENCE); + return obj; +} + +static JSClassID js_hash_state_class_id; + +typedef struct { + crypto_hash_sha512_state h; + int finalized; +} TART_HashState; + + +static void js_hash_state_finalizer(JSRuntime *rt, JSValue val) +{ + TART_HashState *s = JS_GetOpaque(val, js_hash_state_class_id); + /* Note: 's' can be NULL in case JS_SetOpaque() was not called */ + js_free_rt(rt, s); +} + +static JSClassDef js_hash_state_class = { + "HashState", + .finalizer = js_hash_state_finalizer, +}; + +static JSValue js_talercrypto_hash_state_init(JSContext *ctx, JSValue this_val, + int argc, JSValueConst *argv) +{ + TART_HashState *hstate; + JSValue obj; + + hstate = js_malloc_rt(JS_GetRuntime(ctx), sizeof (TART_HashState)); + if (!hstate) { + obj = JS_EXCEPTION; + goto done; + } + hstate->finalized = FALSE; + obj = JS_NewObjectClass(ctx, js_hash_state_class_id); + crypto_hash_sha512_init(&hstate->h); + JS_SetOpaque(obj, hstate); + hstate = NULL; + return obj; +done: + if (NULL != hstate) { + js_free_rt(JS_GetRuntime(ctx), hstate); + } + return obj; +} + +static JSValue js_talercrypto_hash_state_update(JSContext *ctx, JSValue this_val, + int argc, JSValueConst *argv) +{ + JSValue state = argv[0]; + JSValue data_val = argv[1]; + TART_HashState *hstate; + uint8_t *data; + size_t data_len; + + hstate = JS_GetOpaque(state, js_hash_state_class_id); + + if (!hstate) { + return JS_ThrowTypeError(ctx, "expected HashState"); + } + + if (hstate->finalized) { + return JS_ThrowTypeError(ctx, "already finalized"); + } + + data = JS_GetArrayBuffer(ctx, &data_len, data_val); + + if (0 != crypto_hash_sha512_update(&hstate->h, data, data_len)) { + return JS_ThrowInternalError(ctx, "hashing failed"); + } + + return JS_UNDEFINED; +} + +static JSValue js_talercrypto_hash_state_finish(JSContext *ctx, JSValue this_val, + int argc, JSValueConst *argv) +{ + JSValue state = argv[0]; + TART_HashState *hstate; + uint8_t hashval[crypto_hash_sha512_BYTES]; + + hstate = JS_GetOpaque(state, js_hash_state_class_id); + + if (!hstate) { + return JS_ThrowTypeError(ctx, "expected HashState"); + } + + if (hstate->finalized) { + return JS_ThrowTypeError(ctx, "already finalized"); + } + + if (0 != crypto_hash_sha512_final(&hstate->h, hashval)) { + return JS_ThrowInternalError(ctx, "hashing failed"); + } + + hstate->finalized = TRUE; + + return make_js_ta_copy(ctx, hashval, crypto_hash_sha512_BYTES); +} + static const JSCFunctionListEntry tart_talercrypto_funcs[] = { + JS_CFUNC_DEF("structuredClone", 1, js_structured_clone), JS_CFUNC_DEF("encodeUtf8", 1, js_encode_utf8), JS_CFUNC_DEF("decodeUtf8", 1, js_decode_utf8), JS_CFUNC_DEF("randomBytes", 1, js_random_bytes), JS_CFUNC_DEF("encodeCrock", 1, js_talercrypto_encode_crock), JS_CFUNC_DEF("decodeCrock", 1, js_talercrypto_decode_crock), JS_CFUNC_DEF("hash", 1, js_talercrypto_hash), + JS_CFUNC_DEF("hashStateInit", 0, js_talercrypto_hash_state_init), + JS_CFUNC_DEF("hashStateUpdate", 2, js_talercrypto_hash_state_update), + JS_CFUNC_DEF("hashStateFinish", 1, js_talercrypto_hash_state_finish), JS_CFUNC_DEF("eddsaGetPublic", 1, js_talercrypto_eddsa_key_get_public), JS_CFUNC_DEF("ecdheGetPublic", 1, js_talercrypto_ecdhe_key_get_public), JS_CFUNC_DEF("eddsaSign", 2, js_talercrypto_eddsa_sign), @@ -1207,7 +1326,11 @@ static const JSCFunctionListEntry tart_talercrypto_funcs[] = { }; static int tart_talercrypto_init(JSContext *ctx, JSModuleDef *m) -{ +{ + /* create the HashState class */ + JS_NewClassID(&js_hash_state_class_id); + JS_NewClass(JS_GetRuntime(ctx), js_hash_state_class_id, &js_hash_state_class); + return JS_SetModuleExportList(ctx, m, tart_talercrypto_funcs, countof(tart_talercrypto_funcs)); }