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:
| M | tart_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));
}