commit b577ea6aeb16f983f05ddd081aa8c9d681932d41
parent 1f14415a426e2ba94575eb7e34db3da941b9f62c
Author: Florian Dold <florian@dold.me>
Date: Wed, 16 Nov 2022 13:00:39 +0100
wip
Diffstat:
| M | quickjs-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) {