quickjs-tart

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

commit b577ea6aeb16f983f05ddd081aa8c9d681932d41
parent 1f14415a426e2ba94575eb7e34db3da941b9f62c
Author: Florian Dold <florian@dold.me>
Date:   Wed, 16 Nov 2022 13:00:39 +0100

wip

Diffstat:
Mquickjs-libc.c | 273++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++---------
1 file changed, 242 insertions(+), 31 deletions(-)

diff --git a/quickjs-libc.c b/quickjs-libc.c @@ -27,6 +27,7 @@ #include <stdarg.h> #include <inttypes.h> #include <string.h> +#include <ctype.h> #include <assert.h> #include <unistd.h> #include <errno.h> @@ -3985,6 +3986,8 @@ static JSValue js_print(JSContext *ctx, JSValueConst this_val, return JS_UNDEFINED; } +// === begin Taler stuff here === + static JSValue js_encode_utf8(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv) { @@ -4014,54 +4017,256 @@ static JSValue js_random_bytes(JSContext *ctx, JSValueConst this_val, return buf; } -static JSValue js_talercrypto_encode_crock(JSContext *ctx, JSValue this_val, - int argc, JSValueConst *argv) +/** + * Get the decoded value corresponding to a character according to Crockford + * Base32 encoding. + * + * @param a a character + * @return corresponding numeric value + */ +static unsigned int +getValue__ (unsigned char a) { + unsigned int dec; + + switch (a) + { + case 'O': + case 'o': + a = '0'; + break; + + case 'i': + case 'I': + case 'l': + case 'L': + a = '1'; + break; + + /* also consider U to be V */ + case 'u': + case 'U': + a = 'V'; + break; + + default: + break; + } + if ((a >= '0') && (a <= '9')) + return a - '0'; + if ((a >= 'a') && (a <= 'z')) + a = toupper (a); + /* return (a - 'a' + 10); */ + dec = 0; + if ((a >= 'A') && (a <= 'Z')) + { + if ('I' < a) + dec++; + if ('L' < a) + dec++; + if ('O' < a) + dec++; + if ('U' < a) + dec++; + return(a - 'A' + 10 - dec); + } + return -1; } -static JSValue js_talercrypto_decode_crock(JSContext *ctx, JSValue this_val, +static JSValue js_talercrypto_encode_crock(JSContext *ctx, JSValue this_val, int argc, JSValueConst *argv) { -} + size_t size; + uint8_t *buf; + uint8_t *out = NULL; + size_t out_size; + // 32 characters for encoding + static char *encTable__ = "0123456789ABCDEFGHJKMNPQRSTVWXYZ"; + unsigned int wpos; + unsigned int rpos; + unsigned int bits; + unsigned int vbit; + const unsigned char *udata; + JSValue ret_val; -/** - * eddsaKeyCreate: () => ArrayBuffer - */ -static JSValue js_talercrypto_eddsa_key_create(JSContext *ctx, JSValue this_val, - int argc, JSValueConst *argv) -{ -} + ret_val = JS_UNDEFINED; -static JSValue js_talercrypto_eddsa_key_get_public(JSContext *ctx, JSValue this_val, - int argc, JSValueConst *argv) -{ -} + buf = JS_GetArrayBuffer(ctx, &size, argv[0]); -static JSValue js_talercrypto_eddsa_sign(JSContext *ctx, JSValue this_val, - int argc, JSValueConst *argv) -{ + if (!buf) { + goto exception; + } + + assert (size < SIZE_MAX / 8 - 4); + out_size = (size * 8 + 4) / 5; + + out = malloc (out_size); + if (!out) { + goto exception; + } + + udata = buf; + if (out_size < (size * 8 + 4) / 5) { + goto exception; + } + vbit = 0; + wpos = 0; + rpos = 0; + bits = 0; + while ((rpos < size) || (vbit > 0)) + { + if ((rpos < size) && (vbit < 5)) + { + bits = (bits << 8) | udata[rpos++]; /* eat 8 more bits */ + vbit += 8; + } + if (vbit < 5) + { + bits <<= (5 - vbit); /* zero-padding */ + assert (vbit == ((size * 8) % 5)); + vbit = 5; + } + if (wpos >= out_size) + { + goto exception; + } + out[wpos++] = encTable__[(bits >> (vbit - 5)) & 31]; + vbit -= 5; + } + assert (0 == vbit); + if (wpos < out_size) + out[wpos] = '\0'; + + ret_val = JS_NewString(ctx, out); + +done: + if (NULL != out) { + free(out); + } + return ret_val; +exception: + ret_val = JS_EXCEPTION; + goto done; } -static JSValue js_talercrypto_eddsa_verify(JSContext *ctx, JSValue this_val, +static JSValue js_talercrypto_decode_crock(JSContext *ctx, JSValue this_val, int argc, JSValueConst *argv) { -} + size_t rpos; + size_t wpos; + unsigned int bits; + unsigned int vbit; + int ret; + int shift; + size_t enclen; + size_t encoded_len; + const char *enc; + JSValue ret_val = JS_UNDEFINED; + unsigned char *uout = NULL; + size_t out_size; -static JSValue js_talercrypto_kx_ecdhe_eddsa(JSContext *ctx, JSValue this_val, - int argc, JSValueConst *argv) -{ -} + enc = JS_ToCStringLen2(ctx, &enclen, argv[0], FALSE); + if (!enc) { + goto exception; + } -static JSValue js_talercrypto_kx_eddsa_ecdhe(JSContext *ctx, JSValue this_val, - int argc, JSValueConst *argv) -{ -} + out_size = (enclen * 5) / 8; + uout = malloc(out_size); + assert (out_size < SIZE_MAX / 8); + encoded_len = out_size * 8; + wpos = out_size; + rpos = enclen; + if ((encoded_len % 5) > 0) + { + vbit = encoded_len % 5; /* padding! */ + shift = 5 - vbit; + bits = (ret = getValue__ (enc[--rpos])) >> shift; + } + else + { + vbit = 5; + shift = 0; + bits = (ret = getValue__ (enc[--rpos])); + } + if ((encoded_len + shift) / 5 != enclen) { + goto exception; + } -static JSValue js_talercrypto_hash(JSContext *ctx, JSValue this_val, - int argc, JSValueConst *argv) -{ + if (-1 == ret) { + goto exception; + } + while (wpos > 0) + { + if (0 == rpos) + { + goto exception; + } + bits = ((ret = getValue__ (enc[--rpos])) << vbit) | bits; + if (-1 == ret) { + goto exception; + } + vbit += 5; + if (vbit >= 8) + { + uout[--wpos] = (unsigned char) bits; + bits >>= 8; + vbit -= 8; + } + } + if ((0 != rpos) || (0 != vbit)) { + goto exception; + } + ret_val = JS_NewArrayBufferCopy(ctx, uout, out_size); +done: + JS_FreeCString(ctx, enc); + if (uout) { + free(uout); + } + return ret_val; +exception: + ret_val = JS_EXCEPTION; + goto done; } +// +///** +// * eddsaKeyCreate: () => ArrayBuffer +// */ +//static JSValue js_talercrypto_eddsa_key_create(JSContext *ctx, JSValue this_val, +// int argc, JSValueConst *argv) +//{ +//} +// +//static JSValue js_talercrypto_eddsa_key_get_public(JSContext *ctx, JSValue this_val, +// int argc, JSValueConst *argv) +//{ +//} +// +//static JSValue js_talercrypto_eddsa_sign(JSContext *ctx, JSValue this_val, +// int argc, JSValueConst *argv) +//{ +//} +// +//static JSValue js_talercrypto_eddsa_verify(JSContext *ctx, JSValue this_val, +// int argc, JSValueConst *argv) +//{ +//} +// +//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) +//{ +//} +// +//static JSValue js_talercrypto_hash(JSContext *ctx, JSValue this_val, +// int argc, JSValueConst *argv) +//{ +//} + static JSValue js_decode_utf8(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv) { @@ -4074,6 +4279,8 @@ static JSValue js_decode_utf8(JSContext *ctx, JSValueConst this_val, return JS_NewStringLen(ctx, (char *) utf8_buf, psize); } +// === end Taler stuff === + void js_std_add_helpers(JSContext *ctx, int argc, char **argv) { JSValue global_obj, console, args; @@ -4093,6 +4300,10 @@ void js_std_add_helpers(JSContext *ctx, int argc, char **argv) JS_NewCFunction(ctx, js_decode_utf8, "_decodeUtf8", 1)); JS_SetPropertyStr(ctx, global_obj, "_randomBytes", JS_NewCFunction(ctx, js_random_bytes, "_randomBytes", 1)); + JS_SetPropertyStr(ctx, global_obj, "_encodeCrock", + JS_NewCFunction(ctx, js_talercrypto_encode_crock, "_encodeCrock", 1)); + JS_SetPropertyStr(ctx, global_obj, "_decodeCrock", + JS_NewCFunction(ctx, js_talercrypto_decode_crock, "_decodeCrock", 1)); /* same methods as the mozilla JS shell */ if (argc >= 0) {