quickjs-tart

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

tart_module.c (59632B)


      1 /*
      2    This file is part of GNU Taler
      3    Copyright (C) 2022 Taler Systems SA
      4 
      5    GNU Taler is free software; you can redistribute it and/or modify it under the
      6    terms of the GNU Affero General Public License as published by the Free Software
      7    Foundation; either version 3, or (at your option) any later version.
      8 
      9    GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY
     10    WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
     11    A PARTICULAR PURPOSE.  See the GNU Affero General Public License for more details.
     12 
     13    You should have received a copy of the GNU Affero General Public License along with
     14    GNU Taler; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>
     15  */
     16 
     17 #include "quickjs/cutils.h"
     18 #include "quickjs/list.h"
     19 #include "quickjs/quickjs-libc.h"
     20 
     21 #include <sodium.h>
     22 #include <mbedtls/hkdf.h>
     23 #include <mbedtls/bignum.h>
     24 #include <mbedtls/error.h>
     25 
     26 #include <ctype.h>
     27 #include <string.h>
     28 #include <assert.h>
     29 
     30 #include <arpa/inet.h>
     31 
     32 #if defined(__APPLE__)
     33 #include <sqlite3.h>
     34 #else
     35 #include "sqlite3/sqlite3.h"
     36 #endif
     37 
     38 static JSValue js_encode_utf8(JSContext *ctx, JSValueConst this_val,
     39                               int argc, JSValueConst *argv)
     40 {
     41     const char *str;
     42     size_t len;
     43     JSValue buf;
     44     str = JS_ToCStringLen2(ctx, &len, argv[0], FALSE);
     45     // FIXME: Don't copy buffer but pass destructor function
     46     buf = JS_NewArrayBufferCopy(ctx, (const uint8_t*) str, len);
     47     JS_FreeCString(ctx, str);
     48     return buf;
     49 }
     50 
     51 static JSValue js_random_bytes(JSContext *ctx, JSValueConst this_val,
     52                                int argc, JSValueConst *argv)
     53 {
     54     uint32_t nbytes;
     55     JSValue buf;
     56     if (0 != JS_ToUint32(ctx, &nbytes, argv[0])) {
     57         return JS_EXCEPTION;
     58     }
     59     {
     60         uint8_t randbuf[nbytes];
     61         randombytes_buf (randbuf, nbytes);
     62         buf = JS_NewArrayBufferCopy(ctx, randbuf, nbytes);
     63     }
     64     return buf;
     65 }
     66 
     67 /**
     68  * Get the decoded value corresponding to a character according to Crockford
     69  * Base32 encoding.
     70  *
     71  * @param a a character
     72  * @return corresponding numeric value
     73  */
     74 static unsigned int
     75 getValue__ (unsigned char a)
     76 {
     77     unsigned int dec;
     78 
     79     switch (a)
     80     {
     81     case 'O':
     82     case 'o':
     83         a = '0';
     84         break;
     85 
     86     case 'i':
     87     case 'I':
     88     case 'l':
     89     case 'L':
     90         a = '1';
     91         break;
     92 
     93     /* also consider U to be V */
     94     case 'u':
     95     case 'U':
     96         a = 'V';
     97         break;
     98 
     99     default:
    100         break;
    101     }
    102     if ((a >= '0') && (a <= '9'))
    103         return a - '0';
    104     if ((a >= 'a') && (a <= 'z'))
    105         a = toupper (a);
    106     /* return (a - 'a' + 10); */
    107     dec = 0;
    108     if ((a >= 'A') && (a <= 'Z'))
    109     {
    110         if ('I' < a)
    111             dec++;
    112         if ('L' < a)
    113             dec++;
    114         if ('O' < a)
    115             dec++;
    116         if ('U' < a)
    117             dec++;
    118         return(a - 'A' + 10 - dec);
    119     }
    120     return -1;
    121 }
    122 
    123 static JSValue js_talercrypto_encode_crock(JSContext *ctx, JSValue this_val,
    124                                            int argc, JSValueConst *argv)
    125 {
    126     size_t size;
    127     uint8_t *buf;
    128     uint8_t *out = NULL;
    129     size_t out_size;
    130     // 32 characters for encoding
    131     static char *encTable__ = "0123456789ABCDEFGHJKMNPQRSTVWXYZ";
    132     unsigned int wpos;
    133     unsigned int rpos;
    134     unsigned int bits;
    135     unsigned int vbit;
    136     const unsigned char *udata;
    137     JSValue ret_val;
    138 
    139     ret_val = JS_UNDEFINED;
    140 
    141     buf = JS_GetArrayBuffer(ctx, &size, argv[0]);
    142 
    143     if (!buf) {
    144         goto exception;
    145     }
    146 
    147     assert (size < SIZE_MAX / 8 - 4);
    148     out_size = size * 8;
    149 
    150     if (out_size % 5 > 0)
    151         out_size += 5 - out_size % 5;
    152     out_size /= 5;
    153 
    154     out = malloc (out_size + 1);
    155     memset (out, 0, out_size + 1);
    156     if (!out) {
    157         goto exception;
    158     }
    159 
    160     udata = buf;
    161     if (out_size < (size * 8 + 4) / 5) {
    162         goto exception;
    163     }
    164     vbit = 0;
    165     wpos = 0;
    166     rpos = 0;
    167     bits = 0;
    168     while ((rpos < size) || (vbit > 0))
    169     {
    170         if ((rpos < size) && (vbit < 5))
    171         {
    172             /* eat 8 more bits */
    173             bits = (bits << 8) | udata[rpos++];     
    174             vbit += 8;
    175         }
    176         if (vbit < 5)
    177         {
    178             bits <<= (5 - vbit);     /* zero-padding */
    179             assert (vbit == ((size * 8) % 5));
    180             vbit = 5;
    181         }
    182         if (wpos >= out_size)
    183         {
    184             goto exception;
    185         }
    186         out[wpos++] = encTable__[(bits >> (vbit - 5)) & 31];
    187         vbit -= 5;
    188     }
    189     assert (0 == vbit);
    190     if (wpos < out_size) {
    191         out[wpos] = '\0';
    192     }
    193 
    194     ret_val = JS_NewString(ctx, (char *) out);
    195 
    196 done:
    197     if (NULL != out) {
    198         free(out);
    199     }
    200     return ret_val;
    201 exception:
    202     ret_val = JS_EXCEPTION;
    203     goto done;
    204 }
    205 
    206 static JSValue js_talercrypto_decode_crock(JSContext *ctx, JSValue this_val,
    207                                            int argc, JSValueConst *argv)
    208 {
    209     size_t rpos;
    210     size_t wpos;
    211     unsigned int bits;
    212     unsigned int vbit;
    213     int ret;
    214     int shift;
    215     size_t enclen;
    216     size_t encoded_len;
    217     const char *enc;
    218     JSValue ret_val = JS_UNDEFINED;
    219     unsigned char *uout = NULL;
    220     size_t out_size;
    221     JSValue abuf;
    222 
    223     enc = JS_ToCStringLen2(ctx, &enclen, argv[0], FALSE);
    224     if (!enc) {
    225         goto exception;
    226     }
    227 
    228     out_size = (enclen * 5) / 8;
    229     encoded_len = out_size * 8;
    230     uout = malloc(out_size);
    231     assert (out_size < SIZE_MAX / 8);
    232     wpos = out_size;
    233     rpos = enclen;
    234     if ((encoded_len % 5) > 0)
    235     {
    236         vbit = encoded_len % 5;   /* padding! */
    237         shift = 5 - vbit;
    238         bits = (ret = getValue__ (enc[--rpos])) >> shift;
    239     }
    240     else
    241     {
    242         vbit = 5;
    243         shift = 0;
    244         bits = (ret = getValue__ (enc[--rpos]));
    245     }
    246     if ((encoded_len + shift) / 5 != enclen) {
    247         JS_ThrowTypeError(ctx, "wrong encoded length");
    248         goto exception;
    249     }
    250 
    251     if (-1 == ret) {
    252         JS_ThrowTypeError(ctx, "invalid character in encoding");
    253         goto exception;
    254     }
    255     while (wpos > 0)
    256     {
    257         if (0 == rpos)
    258         {
    259             goto exception;
    260         }
    261         bits = ((ret = getValue__ (enc[--rpos])) << vbit) | bits;
    262         if (-1 == ret) {
    263             goto exception;
    264         }
    265         vbit += 5;
    266         if (vbit >= 8)
    267         {
    268             uout[--wpos] = (unsigned char) bits;
    269             bits >>= 8;
    270             vbit -= 8;
    271         }
    272     }
    273     if ((0 != rpos) || (0 != vbit)) {
    274         JS_ThrowTypeError(ctx, "rpos or vbit not zero");
    275         goto exception;
    276     }
    277     abuf = JS_NewArrayBufferCopy(ctx, uout, out_size);
    278     if (JS_IsException(abuf)) {
    279         goto exception;
    280     }
    281     ret_val = JS_NewTypedArraySimple(ctx, abuf, 1);
    282 done:
    283     JS_FreeCString(ctx, enc);
    284     if (uout) {
    285         free(uout);
    286     }
    287     return ret_val;
    288 exception:
    289     ret_val = JS_EXCEPTION;
    290     goto done;
    291 }
    292 
    293 uint8_t *expect_fixed_buffer(JSContext *ctx,
    294                              JSValue val, size_t len,
    295                              const char *msg)
    296 {
    297     uint8_t *buf;
    298     size_t sz;
    299 
    300     buf = JS_GetArrayBuffer(ctx, &sz, val);
    301     if (!buf) {
    302         return NULL;
    303     }
    304     if (sz != len) {
    305         JS_ThrowTypeError(ctx, "invalid length for %s", msg);
    306         return NULL;
    307     }
    308     return buf;
    309 }
    310 
    311 int
    312 expect_mpi(JSContext *ctx,
    313            JSValue val,
    314            const char *msg,
    315            mbedtls_mpi *ret_mpi)
    316 {
    317     uint8_t *buf;
    318     size_t sz;
    319 
    320     buf = JS_GetArrayBuffer(ctx, &sz, val);
    321     if (!buf) {
    322         return -1;
    323     }
    324     if (0 != mbedtls_mpi_read_binary(ret_mpi, buf, sz)) {
    325         return -1;
    326     }
    327     return 0;
    328 }
    329 
    330 #define CHECK(x) do { if (!(x)) { abort(); } } while (0)
    331 
    332 typedef struct {
    333     mbedtls_mpi N;
    334     mbedtls_mpi e;
    335 } RsaPub;
    336 
    337 typedef uint8_t BlindingKeySecret[32];
    338 typedef uint8_t HashCode[64];
    339 
    340 int
    341 rsa_public_key_decode(RsaPub *pkey, uint8_t *inbuf, size_t inbuf_len)
    342 {
    343     size_t sz;
    344     uint8_t *p; /* read pointer */
    345     size_t mod_len;
    346     size_t exp_len;
    347     int ret;
    348 
    349     CHECK(NULL != pkey);
    350     if (inbuf_len < 4) {
    351         ret = -1;
    352         goto cleanup;
    353     }
    354     p = inbuf;
    355     mod_len = ntohs(*((uint16_t *) p));
    356     p += sizeof(uint16_t);
    357     exp_len = ntohs(*((uint16_t *) p));
    358     sz = 4 + mod_len + exp_len;
    359     if (sz != inbuf_len) {
    360         ret = -1;
    361         goto cleanup;
    362     }
    363     p += sizeof(uint16_t);
    364     MBEDTLS_MPI_CHK(mbedtls_mpi_read_binary(&pkey->N, p, mod_len));
    365     p += mod_len;
    366     MBEDTLS_MPI_CHK(mbedtls_mpi_read_binary(&pkey->e, p, exp_len));
    367 
    368 cleanup:
    369     if (ret != 0) {
    370         mbedtls_mpi_free(&pkey->N);
    371         mbedtls_mpi_free(&pkey->e);
    372     }
    373     return ret;
    374 }
    375 
    376 int
    377 expect_rsa_pub(JSContext *ctx,
    378                JSValue val,
    379                const char *msg,
    380                RsaPub *ret_rsa_pub)
    381 {
    382     uint8_t *rsa_enc;
    383     size_t rsa_enc_len;
    384     int ret = -1;
    385 
    386     rsa_enc = JS_GetArrayBuffer(ctx, &rsa_enc_len, val);
    387     if (!rsa_enc) {
    388         goto cleanup;
    389     }
    390     if (0 != rsa_public_key_decode(ret_rsa_pub, rsa_enc, rsa_enc_len)) {
    391         JS_ThrowTypeError(ctx, "rsa pubkey");
    392         goto cleanup;
    393     }
    394     ret = 0;
    395 cleanup:
    396     return ret;
    397 }
    398 
    399 #define REQUIRE(cond, _label) do { if (!(cond)) { goto _label; } } while (0)
    400 
    401 
    402 static JSValue make_js_ta_copy(JSContext *ctx, uint8_t *data, size_t size)
    403 {
    404     JSValue array_buf;
    405 
    406     array_buf = JS_NewArrayBufferCopy(ctx, data, size);
    407     if (JS_IsException(array_buf)) {
    408         return JS_EXCEPTION;
    409     }
    410     return JS_NewTypedArraySimple(ctx, array_buf, 1);
    411 }
    412 
    413 /**
    414  * Make a JS typed array from an mbedtls MPI.
    415 */
    416 static JSValue make_js_ta_mpi(JSContext *ctx, const mbedtls_mpi *v)
    417 {
    418     JSValue array_buf;
    419     size_t sz;
    420     uint8_t *buf = NULL;
    421     JSValue ret_val;
    422 
    423     sz = mbedtls_mpi_size(v);
    424     buf = malloc(sz);
    425     if (!buf) {
    426         ret_val = JS_EXCEPTION;
    427         goto cleanup;
    428     }
    429 
    430     if (0 != mbedtls_mpi_write_binary(v, buf, sz)) {
    431         ret_val = JS_EXCEPTION;
    432         goto cleanup;
    433     }
    434 
    435     // FIXME(#perf): Don't copy
    436     array_buf = JS_NewArrayBufferCopy(ctx, buf, sz);
    437     if (JS_IsException(array_buf)) {
    438         ret_val = JS_EXCEPTION;
    439         goto cleanup;
    440     }
    441     ret_val = JS_NewTypedArraySimple(ctx, array_buf, 1);
    442 cleanup:
    443     if (buf) {
    444         free(buf);
    445     }
    446     return ret_val;
    447 }
    448 
    449 static JSValue js_talercrypto_hash(JSContext *ctx, JSValue this_val,
    450                                    int argc, JSValueConst *argv)
    451 {
    452     size_t size;
    453     uint8_t *buf;
    454     unsigned char h[crypto_hash_BYTES];
    455 
    456     buf = JS_GetArrayBuffer(ctx, &size, argv[0]);
    457     if (!buf) {
    458         return JS_EXCEPTION;
    459     }
    460     crypto_hash_sha512(h, buf, size);
    461 
    462     return make_js_ta_copy(ctx, h, crypto_hash_BYTES);
    463 }
    464 
    465 static JSValue js_talercrypto_hash_argon2id(JSContext *ctx, JSValue this_val,
    466                                             int argc, JSValueConst *argv)
    467 {
    468     size_t pw_len;
    469     size_t salt_len;
    470     uint32_t iters;
    471     uint32_t mem_size;
    472     uint32_t hash_len;
    473     uint8_t *pw;
    474     uint8_t *salt;
    475     uint8_t *hash = NULL;
    476 
    477     JSValue ret_val;
    478 
    479     // password: Uint8Array
    480     pw = JS_GetArrayBuffer(ctx, &pw_len, argv[0]);
    481     if (!pw) {
    482         goto exception;
    483     }
    484 
    485     // salt: Uint8Array
    486     salt = JS_GetArrayBuffer(ctx, &salt_len, argv[1]);
    487     if (!salt) {
    488         goto exception;
    489     }
    490     if (salt_len != crypto_pwhash_SALTBYTES) {
    491         JS_ThrowTypeError(ctx, "invalid salt size");
    492         goto exception;
    493     }
    494 
    495     // iterations: number
    496     if (0 != JS_ToUint32(ctx, &iters, argv[2])) {
    497         goto exception;
    498     }
    499 
    500     // memorySize: number (kibibytes)
    501     if (0 != JS_ToUint32(ctx, &mem_size, argv[3])) {
    502         goto exception;
    503     }
    504 
    505     // hashLength: number
    506     if (0 != JS_ToUint32(ctx, &hash_len, argv[4])) {
    507         goto exception;
    508     }
    509 
    510     // Check for overflow when converting memory size to bytes
    511     if (((unsigned long long)mem_size * 1024) > UINT32_MAX) {
    512         JS_ThrowTypeError(ctx, "mem_size too large");
    513         goto exception;
    514     }
    515 
    516     hash = malloc(hash_len);
    517     if (NULL == hash) {
    518       goto exception;
    519     }
    520 
    521     if (crypto_pwhash(hash,
    522                       hash_len,
    523                       (const char*) pw,
    524                       pw_len,
    525                       salt,
    526                       iters,
    527                       mem_size * 1024,
    528                       crypto_pwhash_ALG_ARGON2ID13) != 0) {
    529         JS_ThrowInternalError(ctx, "crypto_pwhash() call failed");
    530         goto exception;
    531     }
    532     ret_val = make_js_ta_copy(ctx, hash, hash_len);
    533  done:
    534     if (NULL != hash) {
    535         free(hash);
    536     }
    537     return ret_val;
    538  exception:
    539     ret_val = JS_EXCEPTION;
    540     goto done;
    541 }
    542 
    543 static JSValue js_talercrypto_eddsa_key_get_public(JSContext *ctx, JSValue this_val,
    544                                                    int argc, JSValueConst *argv)
    545 {
    546     JSValue ret;
    547     uint8_t *buf;
    548     unsigned char pk[crypto_sign_PUBLICKEYBYTES];
    549     unsigned char sk[crypto_sign_SECRETKEYBYTES];
    550 
    551     buf = expect_fixed_buffer(ctx, argv[0], crypto_sign_SEEDBYTES,
    552                               "eddsa private key seed");
    553     
    554     if (!buf) {
    555         goto exception;
    556     }
    557 
    558     crypto_sign_seed_keypair(pk, sk, buf);
    559 
    560     ret = make_js_ta_copy(ctx, pk, crypto_sign_PUBLICKEYBYTES);
    561 done:
    562     sodium_memzero(sk, sizeof sk);
    563     return ret;
    564 exception:
    565     ret = JS_EXCEPTION;
    566     goto done;
    567 }
    568 
    569 static JSValue js_talercrypto_ecdhe_key_get_public(JSContext *ctx, JSValue this_val,
    570                                                    int argc, JSValueConst *argv)
    571 {
    572     JSValue ret;
    573     uint8_t *buf;
    574     unsigned char pk[crypto_scalarmult_BYTES];
    575 
    576     buf = expect_fixed_buffer(ctx, argv[0], crypto_sign_SEEDBYTES, "ecdh private key seed");
    577     
    578     if (!buf) {
    579         goto exception;
    580     }
    581 
    582     if (0 != crypto_scalarmult_base(pk, buf)) {
    583         goto exception;
    584     }
    585 
    586     ret = make_js_ta_copy(ctx, pk, crypto_sign_PUBLICKEYBYTES);
    587 done:
    588     buf = NULL;
    589     return ret;
    590 exception:
    591     ret = JS_EXCEPTION;
    592     goto done;
    593 }
    594 
    595 /**
    596  * (msg, priv) => sig
    597  */
    598 static JSValue js_talercrypto_eddsa_sign(JSContext *ctx, JSValue this_val,
    599                                          int argc, JSValueConst *argv)
    600 {
    601     unsigned char *seed;
    602     size_t seed_size;
    603     unsigned char *data;
    604     size_t data_size;
    605     unsigned char sk[crypto_sign_SECRETKEYBYTES];
    606     unsigned char pk[crypto_sign_PUBLICKEYBYTES];
    607     unsigned char sig[64];
    608     int res;
    609 
    610     data = JS_GetArrayBuffer(ctx, &data_size, argv[0]);
    611     if (!data) {
    612         return JS_EXCEPTION;
    613     }
    614 
    615     seed = JS_GetArrayBuffer(ctx, &seed_size, argv[1]);
    616     if (!seed) {
    617         return JS_EXCEPTION;
    618     }
    619     if (seed_size != 32) {
    620         return JS_ThrowTypeError(ctx, "invalid private key seed size");
    621     }
    622 
    623     if (0 != crypto_sign_seed_keypair(pk, sk, seed)) {
    624         return JS_EXCEPTION;
    625     }
    626 
    627     res = crypto_sign_detached((uint8_t *)sig,
    628                                NULL,
    629                                (uint8_t *)data,
    630                                data_size,
    631                                sk);
    632     if (res != 0) {
    633         return JS_EXCEPTION;
    634     }
    635     return make_js_ta_copy(ctx, sig, 64);
    636 }
    637 
    638 /**
    639  * (msg, sig, pub) -> bool
    640  */
    641 static JSValue js_talercrypto_eddsa_verify(JSContext *ctx, JSValue this_val,
    642                                            int argc, JSValueConst *argv)
    643 {
    644     unsigned char *msg;
    645     size_t msg_size;
    646     unsigned char *sig;
    647     size_t sig_size;
    648     unsigned char *pub;
    649     size_t pub_size;
    650     int res;
    651 
    652     msg = JS_GetArrayBuffer(ctx, &msg_size, argv[0]);
    653     if (!msg) {
    654         return JS_EXCEPTION;
    655     }
    656     sig = JS_GetArrayBuffer(ctx, &sig_size, argv[1]);
    657     if (!sig) {
    658         return JS_EXCEPTION;
    659     }
    660     if (sig_size != 64) {
    661         return JS_ThrowTypeError(ctx, "invalid signature size");
    662     }
    663     pub = JS_GetArrayBuffer(ctx, &pub_size, argv[2]);
    664     if (!pub) {
    665         return JS_EXCEPTION;
    666     }
    667     if (pub_size != 32) {
    668         return JS_ThrowTypeError(ctx, "invalid public key size");
    669     }
    670 
    671     res = crypto_sign_verify_detached (sig, msg, msg_size, pub);
    672     return (res == 0) ? JS_TRUE : JS_FALSE;
    673 }
    674 
    675 /**
    676  * Returns 0 on success.
    677  */
    678 static int
    679 kdf(void *okm, size_t okm_len,
    680     const void *ikm, size_t ikm_len,
    681     const void *salt, size_t salt_len,
    682     const void *info, size_t info_len)
    683 {
    684     const mbedtls_md_info_t *md_extract;
    685     const mbedtls_md_info_t *md_expand;
    686     int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
    687     unsigned char prk[MBEDTLS_MD_MAX_SIZE];
    688 
    689     md_extract = mbedtls_md_info_from_type(MBEDTLS_MD_SHA512);
    690     md_expand = mbedtls_md_info_from_type(MBEDTLS_MD_SHA256);
    691     if (NULL == md_extract) {
    692         return -1;
    693     }
    694     if (NULL == md_expand) {
    695         return -1;
    696     }
    697 
    698     ret = mbedtls_hkdf_extract(md_extract, salt, salt_len, ikm, ikm_len, prk);
    699 
    700     if (ret != 0) {
    701         return ret;
    702     }
    703 
    704     ret = mbedtls_hkdf_expand(md_expand, prk, mbedtls_md_get_size(md_extract),
    705                               info, info_len, okm, okm_len);
    706     return ret;
    707 }
    708 
    709 /**
    710  * (outLen, ikm, salt?, info?) -> output
    711  */
    712 static JSValue js_talercrypto_kdf(JSContext *ctx, JSValue this_val,
    713                                   int argc, JSValueConst *argv)
    714 {
    715     size_t salt_len;
    716     size_t ikm_len;
    717     size_t info_len;
    718     size_t okm_len;
    719     uint8_t *salt;
    720     uint8_t *ikm;
    721     uint8_t *info;
    722     uint8_t *okm = NULL;
    723     uint32_t out_bytes;
    724     JSValue ret_val;
    725     int ret;
    726 
    727     if (0 != JS_ToUint32(ctx, &out_bytes, argv[0])) {
    728         goto exception;
    729     }
    730     okm_len = out_bytes;
    731 
    732     ikm = JS_GetArrayBuffer(ctx, &ikm_len, argv[1]);
    733     if (!ikm) {
    734         goto exception;
    735     }
    736 
    737     if (JS_IsUndefined(argv[2])) {
    738         salt = NULL;
    739         salt_len = 0;
    740     } else {
    741         salt = JS_GetArrayBuffer(ctx, &salt_len, argv[2]);
    742         if (!salt) {
    743             goto exception;
    744         }
    745     }
    746 
    747     if (JS_IsUndefined(argv[3])) {
    748         info = NULL;
    749         info_len = 0;
    750     } else {
    751         info = JS_GetArrayBuffer(ctx, &info_len, argv[3]);
    752         if (!info) {
    753             goto exception;
    754         }
    755     }
    756 
    757     okm = malloc(okm_len);
    758 
    759     ret = kdf(okm, okm_len, ikm, ikm_len, salt, salt_len, info, info_len);
    760 
    761     if (ret != 0) {
    762         JS_ThrowInternalError(ctx, "kdf() call failed");
    763         goto exception;
    764     }
    765     ret_val = make_js_ta_copy(ctx, okm, okm_len);
    766 done:
    767     if (NULL != okm) {
    768         free(okm);
    769     }
    770     return ret_val;
    771 exception:
    772     ret_val = JS_EXCEPTION;
    773     goto done;
    774 }
    775 
    776 /**
    777  * (ecdhePriv, eddsaPub) -> keyMaterial
    778  */
    779 static JSValue js_talercrypto_kx_ecdh_eddsa(JSContext *ctx, JSValue this_val,
    780                                             int argc, JSValueConst *argv)
    781 {
    782     JSValue ret_val;
    783     uint8_t p[crypto_scalarmult_BYTES];
    784     uint8_t *ecdh_priv;
    785     uint8_t *eddsa_pub;
    786     uint8_t curve25510_pk[crypto_scalarmult_BYTES];
    787     uint8_t key_material[crypto_hash_BYTES];
    788 
    789     ecdh_priv = expect_fixed_buffer(ctx, argv[0], 32, "ecdhe priv");
    790     REQUIRE(ecdh_priv, exception);
    791 
    792     eddsa_pub = expect_fixed_buffer(ctx, argv[1], 32, "eddsa pub");
    793     REQUIRE(eddsa_pub, exception);
    794 
    795     if (0 != crypto_sign_ed25519_pk_to_curve25519(curve25510_pk, eddsa_pub)) {
    796         goto exception;
    797     }
    798     if (0 != crypto_scalarmult(p, ecdh_priv, curve25510_pk)) {
    799         goto exception;
    800     }
    801     if (0 != crypto_hash(key_material, p, 32)) {
    802         JS_ThrowTypeError(ctx, "hashing failed");
    803         goto exception;
    804     }
    805     ret_val = make_js_ta_copy(ctx, key_material, crypto_hash_BYTES);
    806 done:
    807     return ret_val;
    808 exception:
    809     ret_val = JS_EXCEPTION;
    810     goto done;
    811 }
    812 
    813 /**
    814  * (eddsaPriv, ecdhePub) -> keyMaterial
    815  */
    816 static JSValue js_talercrypto_kx_eddsa_ecdh(JSContext *ctx, JSValue this_val,
    817                                             int argc, JSValueConst *argv)
    818 {
    819     JSValue ret_val;
    820     uint8_t *priv;
    821     uint8_t *pub;
    822     uint8_t hc[crypto_hash_BYTES];
    823     uint8_t a[crypto_scalarmult_SCALARBYTES];
    824     uint8_t p[crypto_scalarmult_BYTES];
    825     uint8_t key_material[crypto_hash_BYTES];
    826 
    827     priv = expect_fixed_buffer(ctx, argv[0], 32, "eddsa priv");
    828     REQUIRE(priv, exception);
    829     pub = expect_fixed_buffer(ctx, argv[1], 32, "ecdh pub");
    830     REQUIRE(pub, exception);
    831 
    832     crypto_hash(hc, priv, 32);
    833     memcpy (a, &hc, 32);
    834     if (0 != crypto_scalarmult(p, a, pub)) {
    835         goto exception;
    836     }
    837     crypto_hash(key_material, p, crypto_scalarmult_BYTES);
    838     ret_val = make_js_ta_copy(ctx, key_material, crypto_hash_BYTES);
    839 done:
    840     return ret_val;
    841 exception:
    842     ret_val = JS_EXCEPTION;
    843     goto done;
    844 }
    845 
    846 /** FIXME: Should return int */
    847 void
    848 kdf_mod_mpi(mbedtls_mpi *r,
    849             const mbedtls_mpi *n,
    850             const void *xts, size_t xts_len,
    851             const void *skm, size_t skm_len,
    852             const char *ctx)
    853 {
    854     int rc;
    855     size_t nbits;
    856     uint16_t ctr;
    857     size_t ctxlen = strlen(ctx);
    858     size_t my_ctx_len = ctxlen + 2;
    859     unsigned char *my_ctx = malloc(my_ctx_len);
    860     uint16_t *ctr_nbo_p = (uint16_t *) (my_ctx + ctxlen);
    861 
    862     memcpy(my_ctx, ctx, ctxlen);
    863 
    864     nbits = mbedtls_mpi_bitlen(n);
    865     ctr = 0;
    866     while (1) {
    867         /* Not clear if n is always divisible by 8 */
    868         size_t bsize = (nbits - 1) / 8 + 1;
    869         uint8_t buf[bsize];
    870 
    871         *ctr_nbo_p = htons (ctr);
    872 
    873         rc = kdf (buf, bsize,
    874                   skm, skm_len,
    875                   xts, xts_len,
    876                   my_ctx, my_ctx_len);
    877         CHECK(0 == rc);
    878         rc = mbedtls_mpi_read_binary(r, buf, bsize);
    879         CHECK(0 == rc);
    880         while (1) {
    881             size_t rlen = mbedtls_mpi_bitlen(r);
    882             if (rlen <= nbits) {
    883                 break;
    884             }
    885             mbedtls_mpi_set_bit(r, rlen - 1, 0);
    886         }
    887         ++ctr;
    888         /* We reject this FDH if either r > n and retry with another ctr */
    889         if (0 > mbedtls_mpi_cmp_mpi (r, n)) {
    890             break;
    891         }
    892         mbedtls_mpi_free (r);
    893     }
    894     free(my_ctx);
    895 }
    896 
    897 
    898 /**
    899  * Test for malicious RSA key.
    900  *
    901  * Assuming n is an RSA modulous and r is generated using a call to
    902  * GNUNET_CRYPTO_kdf_mod_mpi, if gcd(r,n) != 1 then n must be a
    903  * malicious RSA key designed to deanomize the user.
    904  *
    905  * @param r KDF result
    906  * @param n RSA modulus
    907  * @return 0 if gcd(r,n) = 1, 1 means RSA key is malicious, negative is syserror
    908  */
    909 static int
    910 rsa_gcd_validate (mbedtls_mpi *r,
    911                   const mbedtls_mpi *n)
    912 {
    913     mbedtls_mpi g;
    914     int ret;
    915 
    916     mbedtls_mpi_init(&g);
    917     MBEDTLS_MPI_CHK(mbedtls_mpi_gcd(&g, r, n));
    918 
    919     if (mbedtls_mpi_cmp_int(&g, 1) == 0) {
    920         ret = 0;
    921     } else {
    922         goto cleanup;
    923     }
    924 
    925 cleanup:
    926     mbedtls_mpi_free(&g);
    927     return ret;
    928 }
    929 
    930 
    931 int
    932 rsa_blinding_key_derive(mbedtls_mpi *r,
    933                         const RsaPub *pkey,
    934                         const BlindingKeySecret *bks)
    935 {
    936     /* Trusts bks' randomness more */
    937     const char *xts = "Blinding KDF extractor HMAC key";
    938 
    939     kdf_mod_mpi(r,
    940                 &pkey->N,
    941                 xts, strlen(xts),
    942                 bks, sizeof(*bks),
    943                 "Blinding KDF");
    944 
    945     if (0 != rsa_gcd_validate (r, &pkey->N)) {
    946         return -1;
    947     }
    948 
    949     return 0;
    950 }
    951 
    952 int
    953 rsa_public_key_encode(const RsaPub *pkey, uint8_t **outbuf, size_t *outbuf_len)
    954 {
    955     size_t sz;
    956     uint8_t *buf;
    957     uint8_t *p; /* write pointer */
    958     size_t mod_len;
    959     size_t exp_len;
    960     int ret;
    961 
    962     *outbuf = NULL;
    963     *outbuf_len = 0;
    964 
    965     mod_len = mbedtls_mpi_size(&pkey->N);
    966     exp_len = mbedtls_mpi_size(&pkey->e);
    967     sz = 2 + 2 + exp_len + mod_len;
    968     buf = malloc(sz);
    969     if (!buf) {
    970         return -1;
    971     }
    972 
    973     p = buf;
    974     *((uint16_t *) p) = htons(mod_len);
    975     p += sizeof (uint16_t);
    976     *((uint16_t *) p) = htons(exp_len);
    977     p += sizeof (uint16_t);
    978     MBEDTLS_MPI_CHK(mbedtls_mpi_write_binary(&pkey->N, p, mod_len));
    979     p += mod_len;
    980     MBEDTLS_MPI_CHK(mbedtls_mpi_write_binary(&pkey->e, p, exp_len));
    981 
    982     *outbuf = buf;
    983     *outbuf_len = sz;
    984 
    985 cleanup:
    986     if (0 != ret) {
    987         free(buf);
    988     }
    989     return ret;
    990 }
    991 
    992 
    993 void
    994 rsa_public_key_init(RsaPub *pkey)
    995 {
    996     CHECK(NULL != pkey);
    997     mbedtls_mpi_init(&pkey->e);
    998     mbedtls_mpi_init(&pkey->N);
    999 }
   1000 
   1001 void
   1002 rsa_public_key_free(RsaPub *pkey)
   1003 {
   1004     if (!pkey) {
   1005         return;
   1006     }
   1007     mbedtls_mpi_free(&pkey->e);
   1008     mbedtls_mpi_free(&pkey->N);
   1009 }
   1010 
   1011 
   1012 int
   1013 rsa_full_domain_hash (mbedtls_mpi *r, const RsaPub *pkey,
   1014                       const HashCode *hash)
   1015 {
   1016     uint8_t *xts;
   1017     size_t xts_len;
   1018 
   1019     /* We key with the public denomination key as a homage to RSA-PSS by
   1020        Mihir Bellare and Phillip Rogaway.  Doing this lowers the degree
   1021        of the hypothetical polyomial-time attack on RSA-KTI created by a
   1022        polynomial-time one-more forgary attack.  Yey seeding! */
   1023     rsa_public_key_encode(pkey, &xts, &xts_len);
   1024 
   1025     kdf_mod_mpi(r,
   1026                 &pkey->N,
   1027                 xts, xts_len,
   1028                 hash, sizeof(*hash),
   1029                 "RSA-FDA FTpsW!");
   1030     free(xts);
   1031     if (0 == rsa_gcd_validate (r, &pkey->N)) {
   1032         return 0;
   1033     }
   1034     return 1;
   1035 }
   1036 
   1037 static int
   1038 rsa_blind(const HashCode *hash,
   1039           const BlindingKeySecret *bks,
   1040           const RsaPub *pkey,
   1041           uint8_t **buf,
   1042           size_t *buf_size)
   1043 {
   1044     mbedtls_mpi bkey, data, r_e, data_r_e;
   1045     size_t outsize;
   1046     uint8_t *outbuf;
   1047     int ret;
   1048 
   1049     CHECK(buf != NULL);
   1050     CHECK(buf_size != NULL);
   1051 
   1052     *buf = NULL;
   1053     *buf_size = 0;
   1054 
   1055     mbedtls_mpi_init(&bkey);
   1056     mbedtls_mpi_init(&data);
   1057     mbedtls_mpi_init(&r_e);
   1058     mbedtls_mpi_init(&data_r_e);
   1059 
   1060     MBEDTLS_MPI_CHK(rsa_full_domain_hash (&data, pkey, hash));
   1061     MBEDTLS_MPI_CHK(rsa_blinding_key_derive (&bkey, pkey, bks));
   1062     MBEDTLS_MPI_CHK(mbedtls_mpi_exp_mod(&r_e, &bkey, &pkey->e, &pkey->N, NULL));
   1063     MBEDTLS_MPI_CHK(mbedtls_mpi_mul_mpi(&data_r_e, &data, &r_e));
   1064     MBEDTLS_MPI_CHK(mbedtls_mpi_mod_mpi(&data_r_e, &data_r_e, &pkey->N));
   1065 
   1066     outsize = (mbedtls_mpi_bitlen(&data_r_e) + 7) / 8;
   1067     outbuf = malloc(outsize);
   1068 
   1069     MBEDTLS_MPI_CHK(mbedtls_mpi_write_binary(&data_r_e, outbuf, outsize));
   1070 
   1071     *buf = outbuf;
   1072     *buf_size = outsize;
   1073     ret = 0;
   1074 
   1075 cleanup:
   1076     mbedtls_mpi_free(&data);
   1077     mbedtls_mpi_free(&bkey);
   1078     mbedtls_mpi_free(&r_e);
   1079     mbedtls_mpi_free(&data_r_e);
   1080     return ret;
   1081 }
   1082 
   1083 int
   1084 rsa_unblind (const mbedtls_mpi *sig_blinded,
   1085              const BlindingKeySecret *bks,
   1086              const RsaPub *pkey,
   1087              mbedtls_mpi *sig_ret)
   1088 {
   1089     mbedtls_mpi bkey, r_inv, ubsig;
   1090     int ret;
   1091 
   1092     mbedtls_mpi_init(&bkey);
   1093     mbedtls_mpi_init(&r_inv);
   1094     mbedtls_mpi_init(&ubsig);
   1095 
   1096     MBEDTLS_MPI_CHK(rsa_blinding_key_derive (&bkey, pkey, bks));
   1097     MBEDTLS_MPI_CHK(mbedtls_mpi_inv_mod(&r_inv, &bkey, &pkey->N));
   1098     MBEDTLS_MPI_CHK(mbedtls_mpi_mul_mpi(&ubsig, sig_blinded, &r_inv));
   1099     MBEDTLS_MPI_CHK(mbedtls_mpi_copy(sig_ret, &ubsig));
   1100 
   1101 cleanup:
   1102     mbedtls_mpi_free(&bkey);
   1103     mbedtls_mpi_free(&r_inv);
   1104     mbedtls_mpi_free(&ubsig);
   1105     return ret;
   1106 }
   1107 
   1108 
   1109 int
   1110 rsa_verify(const HashCode *hash,
   1111            const mbedtls_mpi *sig,
   1112            const RsaPub *pkey)
   1113 {
   1114     mbedtls_mpi r;
   1115     mbedtls_mpi sig_e;
   1116     int ret;
   1117 
   1118     mbedtls_mpi_init(&r);
   1119     mbedtls_mpi_init(&sig_e);
   1120 
   1121     /* Can fail if RSA key is malicious since rsa_gcd_validate failed here.
   1122      * It should have failed during GNUNET_CRYPTO_rsa_blind too though,
   1123      * so the exchange is being malicious in an unfamilair way, maybe
   1124      * just trying to crash us.  Arguably, we've only an internal error
   1125      * though because we should've detected this in our previous call
   1126      * to GNUNET_CRYPTO_rsa_unblind. *///
   1127     MBEDTLS_MPI_CHK(rsa_full_domain_hash(&r, pkey, hash));
   1128 
   1129     MBEDTLS_MPI_CHK(mbedtls_mpi_exp_mod(&sig_e, sig, &pkey->e, &pkey->N, NULL));
   1130 
   1131     if (0 != mbedtls_mpi_cmp_mpi(&r, &sig_e)) {
   1132         ret = -1;
   1133     } else {
   1134         ret = 0;
   1135     }
   1136 
   1137 cleanup:
   1138     mbedtls_mpi_free(&r);
   1139     mbedtls_mpi_free(&sig_e);
   1140     return ret;
   1141 }
   1142 
   1143 
   1144 /**
   1145  * (hmsg, bks, rsaPub) -> blinded
   1146  */
   1147 static JSValue js_talercrypto_rsa_blind(JSContext *ctx, JSValueConst this_val,
   1148                                         int argc, JSValueConst *argv)
   1149 {
   1150     HashCode *hmsg;
   1151     BlindingKeySecret *bks;
   1152     uint8_t *rsa_enc;
   1153     size_t rsa_enc_len;
   1154     RsaPub rsa_pub;
   1155     JSValue ret_val = JS_UNDEFINED;
   1156     uint8_t *out_buf = NULL;
   1157     size_t out_len;
   1158 
   1159     rsa_public_key_init(&rsa_pub);
   1160 
   1161     hmsg = (HashCode *) expect_fixed_buffer(ctx, argv[0], 64, "hmsg");
   1162     if (!hmsg) {
   1163         ret_val = JS_EXCEPTION;
   1164         goto cleanup;
   1165     }
   1166     bks = (BlindingKeySecret *) expect_fixed_buffer(ctx, argv[1], 32, "bks");
   1167     if (!bks) {
   1168         ret_val = JS_EXCEPTION;
   1169         goto cleanup;
   1170     }
   1171     rsa_enc = JS_GetArrayBuffer(ctx, &rsa_enc_len, argv[2]);
   1172     if (!rsa_enc) {
   1173         ret_val = JS_EXCEPTION;
   1174         goto cleanup;
   1175     }
   1176     if (0 != rsa_public_key_decode(&rsa_pub, rsa_enc, rsa_enc_len)) {
   1177         ret_val = JS_ThrowTypeError(ctx, "rsa pubkey");
   1178         goto cleanup;
   1179     }
   1180     if (0 != rsa_blind(hmsg, bks, &rsa_pub, &out_buf, &out_len)) {
   1181         ret_val = JS_ThrowInternalError(ctx, "blinding failed");
   1182         goto cleanup;
   1183     }
   1184 
   1185     ret_val = make_js_ta_copy(ctx, out_buf, out_len);
   1186 cleanup:
   1187     if (NULL != out_buf) {
   1188         free(out_buf);
   1189         out_buf = NULL;
   1190     }
   1191     rsa_public_key_free(&rsa_pub);
   1192     return ret_val;
   1193 }
   1194 
   1195 /**
   1196  * (blindSig, rsaPub, bks) -> ubsig
   1197  */
   1198 static JSValue js_talercrypto_rsa_unblind(JSContext *ctx, JSValueConst this_val,
   1199                                         int argc, JSValueConst *argv)
   1200 {
   1201     JSValue ret_val = JS_UNDEFINED;
   1202     mbedtls_mpi bsig;
   1203     mbedtls_mpi sig_ret;
   1204     RsaPub rsa_pub;
   1205     BlindingKeySecret *bks;
   1206 
   1207     mbedtls_mpi_init(&bsig);
   1208     mbedtls_mpi_init(&sig_ret);
   1209     rsa_public_key_init(&rsa_pub);
   1210 
   1211     if (0 != expect_mpi(ctx, argv[0], "blindSig", &bsig)) {
   1212         ret_val = JS_EXCEPTION;
   1213         goto cleanup;
   1214     }
   1215     if (0 != expect_rsa_pub(ctx, argv[1], "rsaPub", &rsa_pub)) {
   1216         ret_val = JS_EXCEPTION;
   1217         goto cleanup;
   1218     }
   1219     bks = (BlindingKeySecret *) expect_fixed_buffer(ctx, argv[2], 32, "bks");
   1220     if (!bks) {
   1221         ret_val = JS_EXCEPTION;
   1222         goto cleanup;
   1223     }
   1224 
   1225     if (0 != rsa_unblind(&bsig, bks, &rsa_pub, &sig_ret)) {
   1226         ret_val = JS_ThrowInternalError(ctx, "unblinding failed");
   1227         goto cleanup;
   1228     }
   1229 
   1230     ret_val = make_js_ta_mpi(ctx, &sig_ret);
   1231 
   1232 cleanup:
   1233     mbedtls_mpi_free(&bsig);
   1234     mbedtls_mpi_free(&sig_ret);
   1235     rsa_public_key_free(&rsa_pub);
   1236     return ret_val;
   1237 }
   1238 
   1239 /**
   1240  * (hm, rsaSig, rsaPub) -> bool
   1241  */
   1242 static JSValue js_talercrypto_rsa_verify(JSContext *ctx, JSValueConst this_val,
   1243                                         int argc, JSValueConst *argv)
   1244 {
   1245     JSValue ret_val = JS_UNDEFINED;
   1246     HashCode *hmsg;
   1247     mbedtls_mpi sig;
   1248     RsaPub rsa_pub;
   1249 
   1250     mbedtls_mpi_init(&sig);
   1251     rsa_public_key_init(&rsa_pub);
   1252 
   1253     hmsg = (HashCode *) expect_fixed_buffer(ctx, argv[0], 64, "hmsg");
   1254     if (!hmsg) {
   1255         ret_val = JS_EXCEPTION;
   1256         goto cleanup;
   1257     }
   1258 
   1259     if (0 != expect_mpi(ctx, argv[1], "sig", &sig)) {
   1260         ret_val = JS_EXCEPTION;
   1261         goto cleanup;
   1262     }
   1263 
   1264     if (0 != expect_rsa_pub(ctx, argv[2], "rsaPub", &rsa_pub)) {
   1265         ret_val = JS_EXCEPTION;
   1266         goto cleanup;
   1267     }
   1268 
   1269     if (0 != rsa_verify(hmsg, &sig, &rsa_pub)) {
   1270         ret_val = JS_FALSE;
   1271         goto cleanup;
   1272     }
   1273 
   1274     ret_val = JS_TRUE;
   1275 
   1276 cleanup:
   1277     mbedtls_mpi_free(&sig);
   1278     rsa_public_key_free(&rsa_pub);
   1279     return ret_val;
   1280 
   1281 }
   1282 
   1283 // (ArrayBuffer | TypedArray) => string
   1284 static JSValue js_decode_utf8(JSContext *ctx, JSValueConst this_val,
   1285                               int argc, JSValueConst *argv)
   1286 {
   1287     size_t psize;
   1288     uint8_t *utf8_buf;
   1289     JSValue ret_val;
   1290 
   1291     utf8_buf = JS_GetArrayBuffer(ctx, &psize, argv[0]);
   1292     if (NULL == utf8_buf) {
   1293         goto exception;
   1294     }
   1295     return JS_NewStringLen(ctx, (char *) utf8_buf, psize);
   1296 done:
   1297     return ret_val;
   1298 exception:
   1299     ret_val = JS_EXCEPTION;
   1300     goto done;
   1301 }
   1302 
   1303 static JSValue js_structured_clone(JSContext *ctx, JSValueConst this_val,
   1304                                    int argc, JSValueConst *argv)
   1305 {
   1306     uint8_t *buf;
   1307     size_t len;
   1308     JSValue obj;
   1309 
   1310     buf = JS_WriteObject(ctx, &len, argv[0], JS_WRITE_OBJ_REFERENCE);
   1311 
   1312     if (NULL == buf) {
   1313         return JS_EXCEPTION;
   1314     }
   1315 
   1316     obj = JS_ReadObject(ctx, buf, len, JS_WRITE_OBJ_REFERENCE);
   1317     js_free(ctx, buf);
   1318     return obj;
   1319 }
   1320 
   1321 static JSClassID js_hash_state_class_id;
   1322 
   1323 typedef struct {
   1324     crypto_hash_sha512_state h;
   1325     int finalized;
   1326 } TART_HashState;
   1327 
   1328 
   1329 static void js_hash_state_finalizer(JSRuntime *rt, JSValue val)
   1330 {
   1331     TART_HashState *s = JS_GetOpaque(val, js_hash_state_class_id);
   1332     /* Note: 's' can be NULL in case JS_SetOpaque() was not called */
   1333     js_free_rt(rt, s);
   1334 }
   1335 
   1336 static JSClassDef js_hash_state_class = {
   1337     "HashState",
   1338     .finalizer = js_hash_state_finalizer,
   1339 };
   1340 
   1341 static JSValue js_talercrypto_hash_state_init(JSContext *ctx, JSValue this_val,
   1342                                               int argc, JSValueConst *argv)
   1343 {
   1344     TART_HashState *hstate;
   1345     JSValue obj;
   1346 
   1347     hstate = js_malloc_rt(JS_GetRuntime(ctx), sizeof (TART_HashState));
   1348     if (!hstate) {
   1349         obj = JS_EXCEPTION;
   1350         goto done;
   1351     }
   1352     hstate->finalized = FALSE;
   1353     obj = JS_NewObjectClass(ctx, js_hash_state_class_id);
   1354     crypto_hash_sha512_init(&hstate->h);
   1355     JS_SetOpaque(obj, hstate);
   1356     hstate = NULL;
   1357     return obj;
   1358 done:
   1359     if (NULL != hstate) {
   1360         js_free_rt(JS_GetRuntime(ctx), hstate);
   1361     }
   1362     return obj;
   1363 }
   1364 
   1365 static JSValue js_talercrypto_hash_state_update(JSContext *ctx, JSValue this_val,
   1366                                               int argc, JSValueConst *argv)
   1367 {
   1368     JSValue state = argv[0];
   1369     JSValue data_val = argv[1];
   1370     TART_HashState *hstate;
   1371     uint8_t *data;
   1372     size_t data_len;
   1373 
   1374     hstate = JS_GetOpaque(state, js_hash_state_class_id);
   1375 
   1376     if (!hstate) {
   1377         return JS_ThrowTypeError(ctx, "expected HashState");
   1378     }
   1379 
   1380     if (hstate->finalized) {
   1381         return JS_ThrowTypeError(ctx, "already finalized");
   1382     }
   1383 
   1384     data = JS_GetArrayBuffer(ctx, &data_len, data_val);
   1385 
   1386     if (0 != crypto_hash_sha512_update(&hstate->h, data, data_len)) {
   1387         return JS_ThrowInternalError(ctx, "hashing failed");
   1388     }
   1389 
   1390     return JS_UNDEFINED;
   1391 }
   1392 
   1393 static JSValue js_talercrypto_hash_state_finish(JSContext *ctx, JSValue this_val,
   1394                                               int argc, JSValueConst *argv)
   1395 {
   1396     JSValue state = argv[0];
   1397     TART_HashState *hstate;
   1398     uint8_t hashval[crypto_hash_sha512_BYTES];
   1399 
   1400     hstate = JS_GetOpaque(state, js_hash_state_class_id);
   1401 
   1402     if (!hstate) {
   1403         return JS_ThrowTypeError(ctx, "expected HashState");
   1404     }
   1405 
   1406     if (hstate->finalized) {
   1407         return JS_ThrowTypeError(ctx, "already finalized");
   1408     }
   1409 
   1410     if (0 != crypto_hash_sha512_final(&hstate->h, hashval)) {
   1411         return JS_ThrowInternalError(ctx, "hashing failed");
   1412     }
   1413 
   1414     hstate->finalized = TRUE;
   1415 
   1416     return make_js_ta_copy(ctx, hashval, crypto_hash_sha512_BYTES);
   1417 }
   1418 
   1419 static JSClassID js_sqlite3_database_class_id;
   1420 static JSClassID js_sqlite3_statement_class_id;
   1421 
   1422 static void js_sqlite3_database_finalizer(JSRuntime *rt, JSValue val)
   1423 {
   1424     sqlite3 *sqlite3_db;
   1425     sqlite3_db = JS_GetOpaque(val, js_sqlite3_database_class_id);
   1426     (void)sqlite3_close_v2(sqlite3_db);
   1427     JS_SetOpaque(val, NULL);
   1428 }
   1429 
   1430 static void js_sqlite3_statement_finalizer(JSRuntime *rt, JSValue val)
   1431 {
   1432     sqlite3_stmt *stmt;
   1433 
   1434     stmt = JS_GetOpaque(val, js_sqlite3_statement_class_id);
   1435     // FIXME: Check error code and warn?
   1436     sqlite3_finalize(stmt);
   1437     JS_SetOpaque(val, NULL);
   1438 }
   1439 
   1440 static JSClassDef js_sqlite3_database_class = {
   1441     .class_name = "Sqlite3Database",
   1442     .finalizer = js_sqlite3_database_finalizer,
   1443 };
   1444 
   1445 static JSClassDef js_sqlite3_statement_class = {
   1446     .class_name = "Sqlite3Statement",
   1447     .finalizer = js_sqlite3_statement_finalizer,
   1448 };
   1449 
   1450 #define ERRCASE(c) case c: return #c
   1451 
   1452 const char *translate_sqlite3_err_to_string(int errcode)
   1453 {
   1454     switch (errcode) {
   1455         ERRCASE(SQLITE_OK);
   1456         ERRCASE(SQLITE_ERROR);
   1457         ERRCASE(SQLITE_INTERNAL);
   1458         ERRCASE(SQLITE_PERM);
   1459         ERRCASE(SQLITE_ABORT);
   1460         ERRCASE(SQLITE_BUSY);
   1461         ERRCASE(SQLITE_LOCKED);
   1462         ERRCASE(SQLITE_NOMEM);
   1463         ERRCASE(SQLITE_READONLY);
   1464         ERRCASE(SQLITE_INTERRUPT);
   1465         ERRCASE(SQLITE_IOERR);
   1466         ERRCASE(SQLITE_CORRUPT);
   1467         ERRCASE(SQLITE_NOTFOUND);
   1468         ERRCASE(SQLITE_FULL);
   1469         ERRCASE(SQLITE_CANTOPEN);
   1470         ERRCASE(SQLITE_PROTOCOL);
   1471         ERRCASE(SQLITE_EMPTY);
   1472         ERRCASE(SQLITE_SCHEMA);
   1473         ERRCASE(SQLITE_TOOBIG);
   1474         ERRCASE(SQLITE_CONSTRAINT);
   1475         ERRCASE(SQLITE_MISMATCH);
   1476         ERRCASE(SQLITE_MISUSE);
   1477         ERRCASE(SQLITE_NOLFS);
   1478         ERRCASE(SQLITE_AUTH);
   1479         ERRCASE(SQLITE_FORMAT);
   1480         ERRCASE(SQLITE_RANGE);
   1481         ERRCASE(SQLITE_NOTADB);
   1482         ERRCASE(SQLITE_NOTICE);
   1483         ERRCASE(SQLITE_WARNING);
   1484         ERRCASE(SQLITE_ROW);
   1485         ERRCASE(SQLITE_DONE);
   1486         ERRCASE(SQLITE_ERROR_MISSING_COLLSEQ);
   1487         ERRCASE(SQLITE_ERROR_RETRY);
   1488         ERRCASE(SQLITE_ERROR_SNAPSHOT);
   1489         ERRCASE(SQLITE_IOERR_READ);
   1490         ERRCASE(SQLITE_IOERR_SHORT_READ);
   1491         ERRCASE(SQLITE_IOERR_WRITE);
   1492         ERRCASE(SQLITE_IOERR_FSYNC);
   1493         ERRCASE(SQLITE_IOERR_DIR_FSYNC);
   1494         ERRCASE(SQLITE_IOERR_TRUNCATE);
   1495         ERRCASE(SQLITE_IOERR_FSTAT);
   1496         ERRCASE(SQLITE_IOERR_UNLOCK);
   1497         ERRCASE(SQLITE_IOERR_RDLOCK);
   1498         ERRCASE(SQLITE_IOERR_DELETE);
   1499         ERRCASE(SQLITE_IOERR_BLOCKED);
   1500         ERRCASE(SQLITE_IOERR_NOMEM);
   1501         ERRCASE(SQLITE_IOERR_ACCESS);
   1502         ERRCASE(SQLITE_IOERR_CHECKRESERVEDLOCK);
   1503         ERRCASE(SQLITE_IOERR_LOCK);
   1504         ERRCASE(SQLITE_IOERR_CLOSE);
   1505         ERRCASE(SQLITE_IOERR_DIR_CLOSE);
   1506         ERRCASE(SQLITE_IOERR_SHMOPEN);
   1507         ERRCASE(SQLITE_IOERR_SHMSIZE);
   1508         ERRCASE(SQLITE_IOERR_SHMLOCK);
   1509         ERRCASE(SQLITE_IOERR_SHMMAP);
   1510         ERRCASE(SQLITE_IOERR_SEEK);
   1511         ERRCASE(SQLITE_IOERR_DELETE_NOENT);
   1512         ERRCASE(SQLITE_IOERR_MMAP);
   1513         ERRCASE(SQLITE_IOERR_GETTEMPPATH);
   1514         ERRCASE(SQLITE_IOERR_CONVPATH);
   1515         ERRCASE(SQLITE_IOERR_VNODE);
   1516         ERRCASE(SQLITE_IOERR_AUTH);
   1517         ERRCASE(SQLITE_IOERR_BEGIN_ATOMIC);
   1518         ERRCASE(SQLITE_IOERR_COMMIT_ATOMIC);
   1519         ERRCASE(SQLITE_IOERR_ROLLBACK_ATOMIC);
   1520         ERRCASE(SQLITE_IOERR_DATA);
   1521         ERRCASE(SQLITE_IOERR_CORRUPTFS);
   1522         ERRCASE(SQLITE_LOCKED_SHAREDCACHE);
   1523         ERRCASE(SQLITE_LOCKED_VTAB);
   1524         ERRCASE(SQLITE_BUSY_RECOVERY);
   1525         ERRCASE(SQLITE_BUSY_SNAPSHOT);
   1526         ERRCASE(SQLITE_BUSY_TIMEOUT);
   1527         ERRCASE(SQLITE_CANTOPEN_NOTEMPDIR);
   1528         ERRCASE(SQLITE_CANTOPEN_ISDIR);
   1529         ERRCASE(SQLITE_CANTOPEN_FULLPATH);
   1530         ERRCASE(SQLITE_CANTOPEN_CONVPATH);
   1531         ERRCASE(SQLITE_CANTOPEN_DIRTYWAL);
   1532         ERRCASE(SQLITE_CANTOPEN_SYMLINK);
   1533         ERRCASE(SQLITE_CORRUPT_VTAB);
   1534         ERRCASE(SQLITE_CORRUPT_SEQUENCE);
   1535         ERRCASE(SQLITE_CORRUPT_INDEX);
   1536         ERRCASE(SQLITE_READONLY_RECOVERY);
   1537         ERRCASE(SQLITE_READONLY_CANTLOCK);
   1538         ERRCASE(SQLITE_READONLY_ROLLBACK);
   1539         ERRCASE(SQLITE_READONLY_DBMOVED);
   1540         ERRCASE(SQLITE_READONLY_CANTINIT);
   1541         ERRCASE(SQLITE_READONLY_DIRECTORY);
   1542         ERRCASE(SQLITE_ABORT_ROLLBACK);
   1543         ERRCASE(SQLITE_CONSTRAINT_CHECK);
   1544         ERRCASE(SQLITE_CONSTRAINT_COMMITHOOK);
   1545         ERRCASE(SQLITE_CONSTRAINT_FOREIGNKEY);
   1546         ERRCASE(SQLITE_CONSTRAINT_FUNCTION);
   1547         ERRCASE(SQLITE_CONSTRAINT_NOTNULL);
   1548         ERRCASE(SQLITE_CONSTRAINT_PRIMARYKEY);
   1549         ERRCASE(SQLITE_CONSTRAINT_TRIGGER);
   1550         ERRCASE(SQLITE_CONSTRAINT_UNIQUE);
   1551         ERRCASE(SQLITE_CONSTRAINT_VTAB);
   1552         ERRCASE(SQLITE_CONSTRAINT_ROWID);
   1553         ERRCASE(SQLITE_CONSTRAINT_PINNED);
   1554         ERRCASE(SQLITE_CONSTRAINT_DATATYPE);
   1555         ERRCASE(SQLITE_NOTICE_RECOVER_WAL);
   1556         ERRCASE(SQLITE_NOTICE_RECOVER_ROLLBACK);
   1557 #ifdef SQLITE_NOTICE_RBU
   1558         ERRCASE(SQLITE_NOTICE_RBU);
   1559 #endif
   1560         ERRCASE(SQLITE_WARNING_AUTOINDEX);
   1561         ERRCASE(SQLITE_AUTH_USER);
   1562         ERRCASE(SQLITE_OK_LOAD_PERMANENTLY);
   1563         ERRCASE(SQLITE_OK_SYMLINK);
   1564         default:
   1565             return "SQLITE_UNKNOWN_ERRCODE";
   1566     }
   1567 }
   1568 
   1569 
   1570 static JSValue throw_sqlite3_error(JSContext *ctx, sqlite3 *db)
   1571 {
   1572     JSValue obj;
   1573 
   1574     obj = JS_NewError(ctx);
   1575     if (JS_IsException(obj)) {
   1576         /* out of memory: throw JS_NULL to avoid recursing */
   1577         obj = JS_NULL;
   1578         goto done;
   1579     }
   1580 
   1581     JS_DefinePropertyValueStr(
   1582         ctx,
   1583         obj,
   1584         "message",
   1585         JS_NewString(ctx, sqlite3_errmsg(db)),
   1586         JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE);
   1587 
   1588     JS_DefinePropertyValueStr(
   1589         ctx,
   1590         obj,
   1591         "code",
   1592         JS_NewString(ctx, translate_sqlite3_err_to_string(sqlite3_errcode(db))),
   1593         JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE);
   1594 
   1595 done:
   1596     return JS_Throw(ctx, obj);
   1597 }
   1598 
   1599 
   1600 #define MAX_SAFE_INTEGER (((int64_t)1 << 53) - 1)
   1601 #define MIN_SAFE_INTEGER (-(((int64_t)1 << 53) - 1))
   1602 
   1603 // (path: string, options?: { readonly?: boolean = false }) => Sqlite3Database
   1604 static JSValue js_sqlite3_open(JSContext *ctx, JSValue this_val,
   1605                                int argc, JSValueConst *argv)
   1606 {
   1607     JSValue ret_val = JS_UNINITIALIZED;
   1608     JSValue db_obj = JS_UNINITIALIZED;
   1609     const char *filename = NULL;
   1610     sqlite3 *sqlite3_db = NULL;
   1611     int ret;
   1612 
   1613     if (!JS_IsString(argv[0])) {
   1614         ret_val = JS_ThrowTypeError(ctx, "filename argument required");
   1615         goto done;
   1616     }
   1617 
   1618     filename = JS_ToCString(ctx, argv[0]);
   1619 
   1620     if (!filename) {
   1621         ret_val = JS_ThrowTypeError(ctx, "filename argument required");
   1622         goto done;
   1623     }
   1624 
   1625 //    fprintf(stderr, "opening sqlite3 db at %s\n", filename),
   1626     ret = sqlite3_open_v2(filename, &sqlite3_db, SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE, NULL);
   1627     if (SQLITE_OK != ret) {
   1628         if (NULL == sqlite3_db) {
   1629           // sqlite3 was unable to even allocate memory
   1630           ret_val = JS_ThrowInternalError(ctx, "unable to open database (OOM)");
   1631         } else {
   1632           // get error details from DB before we close it
   1633           fprintf(stderr, "sqlite3_open failed: %s / %s\n",
   1634                   sqlite3_errstr(ret),
   1635                   sqlite3_errmsg(sqlite3_db));
   1636           ret_val = throw_sqlite3_error(ctx, sqlite3_db);
   1637           fprintf(stderr, "calling sqlite3 close on failed db\n");
   1638           (void)sqlite3_close_v2(sqlite3_db);
   1639         }
   1640         goto done;
   1641     }
   1642     db_obj = JS_NewObjectClass(ctx, js_sqlite3_database_class_id);
   1643     JS_SetOpaque(db_obj, sqlite3_db);
   1644     ret_val = db_obj;
   1645 done:
   1646     JS_FreeCString(ctx, filename);
   1647     return ret_val;
   1648 }
   1649 
   1650 // (handle: Sqlite3Database) -> undefined
   1651 static JSValue js_sqlite3_close(JSContext *ctx, JSValue this_val,
   1652                                               int argc, JSValueConst *argv)
   1653 {
   1654     JSValue db_handle = argv[0];
   1655     sqlite3 *sqlite3_db;
   1656 
   1657     sqlite3_db = JS_GetOpaque(db_handle, js_sqlite3_database_class_id);
   1658 
   1659     if (!sqlite3_db) {
   1660         return JS_ThrowTypeError(ctx, "invalid sqlite3 database handle");
   1661     }
   1662 
   1663     (void) sqlite3_close_v2(sqlite3_db);
   1664     JS_SetOpaque(db_handle, NULL);
   1665     return JS_UNDEFINED;
   1666 }
   1667 
   1668 // (handle: Sqlite3Database, stmt: string) => Sqlite3Statement
   1669 static JSValue js_sqlite3_prepare(JSContext *ctx, JSValue this_val,
   1670                                               int argc, JSValueConst *argv)
   1671 {
   1672     JSValue db_handle = argv[0];
   1673     JSValue stmt_str = argv[1];
   1674     JSValue ret_val = JS_UNDEFINED;
   1675     JSValue stmt_obj = JS_UNDEFINED;
   1676     int ret;
   1677     sqlite3 *sqlite3_db;
   1678     sqlite3_stmt *stmt;
   1679     const char *stmt_cstr;
   1680     const char *tail;
   1681 
   1682     sqlite3_db = JS_GetOpaque(db_handle, js_sqlite3_database_class_id);
   1683 
   1684     if (!sqlite3_db) {
   1685         return JS_ThrowTypeError(ctx, "invalid sqlite3 database handle");
   1686     }
   1687 
   1688     stmt_cstr = JS_ToCString(ctx, stmt_str);
   1689 
   1690     if (!stmt_cstr) {
   1691         ret_val = JS_ThrowTypeError(ctx, "invalid prepared statement, string expected");
   1692         goto done;
   1693     }
   1694 
   1695     ret = sqlite3_prepare_v3(sqlite3_db, stmt_cstr, (int) strlen(stmt_cstr), 0, &stmt, &tail);
   1696     if (SQLITE_OK != ret) {
   1697         ret_val = JS_ThrowTypeError(ctx, "unable to prepare");
   1698         goto done;
   1699     }
   1700  
   1701     stmt_obj = JS_NewObjectClass(ctx, js_sqlite3_statement_class_id);
   1702     JS_SetOpaque(stmt_obj, stmt);
   1703     ret_val = stmt_obj;
   1704 done:
   1705     JS_FreeCString(ctx, stmt_cstr);
   1706     return ret_val;
   1707 }
   1708 
   1709 
   1710 static JSValue js_sqlite3_finalize(JSContext *ctx, JSValue this_val,
   1711                                               int argc, JSValueConst *argv)
   1712 {
   1713     sqlite3_stmt *stmt;
   1714 
   1715     stmt = JS_GetOpaque(argv[0], js_sqlite3_statement_class_id);
   1716     if (!stmt) {
   1717         return JS_ThrowTypeError(ctx, "unable to finalize (not a statement)");
   1718     }
   1719     // FIXME: Check error code and warn?
   1720     sqlite3_finalize(stmt);
   1721     JS_SetOpaque(argv[0], NULL);
   1722     return JS_UNDEFINED;
   1723 }
   1724 
   1725 static int sql_exec_cb(void *cls, int numcol, char **res, char **colnames) {
   1726     printf("got row with %d columns\n", numcol);
   1727     return 0;
   1728 }
   1729 
   1730 static JSValue js_sqlite3_exec(JSContext *ctx, JSValue this_val,
   1731                                               int argc, JSValueConst *argv)
   1732 {
   1733     sqlite3 *sqlite3_db;
   1734     JSValue db_handle = argv[0];
   1735     JSValue stmt_str = argv[1];
   1736     const char *stmt_cstr = NULL;
   1737     int res;
   1738     char *errmsg = NULL;
   1739     JSValue ret_val = JS_UNDEFINED;
   1740 
   1741     sqlite3_db = JS_GetOpaque(db_handle, js_sqlite3_database_class_id);
   1742     if (!sqlite3_db) {
   1743         JS_ThrowTypeError(ctx, "invalid sqlite3 database handle");
   1744         goto exception;
   1745     }
   1746     stmt_cstr = JS_ToCString(ctx, stmt_str);
   1747     if (!stmt_cstr) {
   1748         goto exception;
   1749     }
   1750     res = sqlite3_exec(sqlite3_db, stmt_cstr, &sql_exec_cb, NULL, &errmsg);
   1751     if (SQLITE_OK != res) {
   1752         throw_sqlite3_error(ctx, sqlite3_db);
   1753         goto exception;
   1754     }
   1755 done:
   1756     sqlite3_free(errmsg);
   1757     JS_FreeCString(ctx, stmt_cstr);
   1758     return ret_val;
   1759 exception:
   1760     ret_val = JS_EXCEPTION;
   1761     goto done;
   1762 }
   1763 
   1764 static int find_param_index(sqlite3_stmt *stmt, const char *name)
   1765 {
   1766     int param_index;
   1767     char *prefixed_name = malloc(strlen(name) + 2);
   1768     memcpy(prefixed_name + 1, name, strlen(name) + 1);
   1769 
   1770     prefixed_name[0] = '$';
   1771     param_index = sqlite3_bind_parameter_index(stmt, prefixed_name);
   1772     if (param_index) {
   1773         goto done;
   1774     }
   1775     prefixed_name[0] = ':';
   1776     param_index = sqlite3_bind_parameter_index(stmt, prefixed_name);
   1777     if (param_index) {
   1778         goto done;
   1779     }
   1780     prefixed_name[0] = '@';
   1781     param_index = sqlite3_bind_parameter_index(stmt, prefixed_name);
   1782     if (param_index) {
   1783         goto done;
   1784     }
   1785 done:
   1786     free(prefixed_name);
   1787     return param_index;
   1788 }
   1789 
   1790 static int bind_from_object(JSContext *ctx, sqlite3_stmt *stmt, JSValueConst obj)
   1791 {
   1792     JSValue val;
   1793     int i;
   1794     uint32_t len = 0; /* len of property table */
   1795     JSPropertyEnum *tab;
   1796     const char *key = NULL;
   1797     int retval = 0;
   1798 
   1799     if (JS_IsUndefined(obj)) {
   1800         return 0;
   1801     }
   1802 
   1803     if (JS_GetOwnPropertyNames(ctx, &tab, &len, obj,
   1804                                JS_GPN_STRING_MASK | JS_GPN_ENUM_ONLY) < 0) {
   1805         JS_ThrowTypeError(ctx, "can't get property names");
   1806         return -1;
   1807     }
   1808 
   1809     for (i = 0; i < len; i++) {
   1810         int param_index;
   1811         val = JS_GetProperty(ctx, obj, tab[i].atom);
   1812         if (JS_IsException(val))
   1813             goto fail;
   1814         key = JS_AtomToCString(ctx, tab[i].atom);
   1815         if (!key) {
   1816             goto fail;
   1817         }
   1818         param_index = find_param_index(stmt, key);
   1819         if (0 == param_index) {
   1820             // JS_ThrowTypeError(ctx, "unable to bind, named param '%s' not found", key);
   1821             //goto fail;
   1822             // We ignore parameters that are bound but not used.
   1823             goto next;
   1824         }
   1825         if (JS_IsNull(val)) {
   1826             sqlite3_bind_null(stmt, param_index);
   1827             goto next;
   1828         }
   1829         if (JS_IsString(val)) {
   1830             const char *cstr;
   1831             cstr = JS_ToCString(ctx, val);
   1832             sqlite3_bind_text(stmt, param_index, cstr, (int) strlen(cstr), SQLITE_TRANSIENT);
   1833             JS_FreeCString(ctx, cstr);
   1834             goto next;
   1835         }
   1836         if (JS_IsNumber(val)) {
   1837             int64_t n;
   1838             JS_ToInt64(ctx, &n, val);
   1839             sqlite3_bind_int64(stmt, param_index, n);
   1840             goto next;
   1841         }
   1842         if (JS_IsArrayBuffer(val)) {
   1843             uint8_t *data;
   1844             size_t size;
   1845             data = JS_GetArrayBuffer(ctx, &size, val);
   1846             if (!data) {
   1847                 goto fail;
   1848             }
   1849             sqlite3_bind_blob(stmt, param_index, data, (int) size, SQLITE_TRANSIENT);
   1850             goto next;
   1851         }
   1852         JS_ThrowTypeError(ctx, "unable to bind, unsupported type for arg %s", key);
   1853         goto fail;
   1854 next:
   1855         JS_FreeCString(ctx, key);
   1856         JS_FreeValue(ctx, val);
   1857     }
   1858 done:
   1859     for (i = 0; i < len; i++) {
   1860         JS_FreeAtom(ctx, tab[i].atom);
   1861     }
   1862     js_free(ctx, tab);
   1863     return retval;
   1864 fail:
   1865     retval = -1;
   1866     goto done;
   1867 }
   1868 
   1869 
   1870 static JSValue js_sqlite3_stmt_run(JSContext *ctx, JSValue this_val,
   1871                                               int argc, JSValueConst *argv)
   1872 {
   1873     JSValue ret_val = JS_UNDEFINED;
   1874     JSValue stmt_handle = argv[0];
   1875     sqlite3_stmt *stmt;
   1876     sqlite3 *db;
   1877     int sqlret;
   1878 
   1879     stmt = JS_GetOpaque(stmt_handle, js_sqlite3_statement_class_id);
   1880     if (!stmt) {
   1881         ret_val = JS_ThrowTypeError(ctx, "invalid sqlite3 database handle");
   1882         goto done;
   1883     }
   1884     db = sqlite3_db_handle(stmt);
   1885     // Reset is not strictly necessary, we do it anyway just to be safe
   1886     sqlret = sqlite3_reset(stmt);
   1887     if (SQLITE_OK != sqlret) {
   1888         fprintf(stderr, "sqlite3_reset failed (in stmt_run): %s\n", sqlite3_errmsg(db));
   1889         ret_val = JS_ThrowTypeError(ctx, "failed to reset");
   1890         goto done;
   1891     }
   1892     sqlret = sqlite3_clear_bindings(stmt);
   1893     if (SQLITE_OK != sqlret) {
   1894         ret_val = JS_ThrowTypeError(ctx, "failed to clear bindings");
   1895         goto done;
   1896     }
   1897     if (argc > 1) {
   1898         if (0 != bind_from_object(ctx, stmt, argv[1])) {
   1899             ret_val = JS_EXCEPTION;
   1900             goto done;
   1901         }
   1902     }
   1903     while (1) {
   1904         sqlret = sqlite3_step(stmt);
   1905         switch (sqlret) {
   1906         case SQLITE_ROW:
   1907             break;
   1908         case SQLITE_DONE: {
   1909             JSValue rowid_val;
   1910             ret_val = JS_NewObject(ctx);
   1911             sqlite3_int64 rowid = sqlite3_last_insert_rowid(db);
   1912             if (rowid >= MIN_SAFE_INTEGER && rowid <= MAX_SAFE_INTEGER) {
   1913                 rowid_val = JS_NewInt64(ctx, rowid);
   1914             } else {
   1915                 rowid_val = JS_NewBigInt64(ctx, rowid);
   1916             }
   1917             JS_SetPropertyStr(ctx, ret_val, "lastInsertRowid", rowid_val);
   1918             sqlret = sqlite3_reset(stmt);
   1919             if (SQLITE_OK != sqlret) {
   1920                 fprintf(stderr, "sqlite3_reset failed (in stmt_run after SQLITE_DONE): %s\n", sqlite3_errmsg(db));
   1921                 JS_FreeValue(ctx, ret_val);
   1922                 ret_val = JS_ThrowTypeError(ctx, "failed to reset");
   1923                 goto done;
   1924             }
   1925             goto done;
   1926         }
   1927         default:
   1928             ret_val = throw_sqlite3_error(ctx, db);
   1929             sqlite3_reset(stmt);
   1930             goto done;
   1931         }
   1932     }
   1933 done:
   1934     return ret_val;
   1935 }
   1936 
   1937 
   1938 static int extract_result_row(JSContext *ctx, sqlite3_stmt *stmt, JSValueConst target)
   1939 {
   1940     int colcount;
   1941     int i;
   1942 
   1943     colcount = sqlite3_column_count(stmt);
   1944 
   1945     for (i = 0; i < colcount; i++) {
   1946         const char *colname = sqlite3_column_name(stmt, i);
   1947         int coltype = sqlite3_column_type(stmt, i);
   1948         switch (coltype) {
   1949         case SQLITE_INTEGER: {
   1950             int64_t val = sqlite3_column_int64(stmt, i);
   1951             if (val > MAX_SAFE_INTEGER || val < MIN_SAFE_INTEGER) {
   1952                 JS_SetPropertyStr(ctx, target, colname, JS_NewBigInt64(ctx, val));
   1953             } else {
   1954                 JS_SetPropertyStr(ctx, target, colname, JS_NewInt64(ctx, val));
   1955             }
   1956             break;
   1957         }
   1958         case SQLITE_FLOAT: {
   1959             double val = sqlite3_column_double(stmt, i);
   1960             JS_SetPropertyStr(ctx, target, colname, JS_NewFloat64(ctx, val));
   1961             break;
   1962         }
   1963         case SQLITE_BLOB: {
   1964             JSValue abuf;
   1965             const uint8_t *blobdata = sqlite3_column_blob(stmt, i);
   1966             size_t bloblen = sqlite3_column_bytes(stmt, i);
   1967             abuf = JS_NewArrayBufferCopy(ctx, blobdata, bloblen);
   1968             JS_SetPropertyStr(ctx, target, colname, JS_NewTypedArraySimple(ctx, abuf, 1));
   1969             break;
   1970         }
   1971         case SQLITE_NULL:
   1972             JS_SetPropertyStr(ctx, target, colname, JS_NULL);
   1973             break;
   1974         case SQLITE_TEXT: {
   1975             const char *text = (const char *) sqlite3_column_text(stmt, i);
   1976             JS_SetPropertyStr(ctx, target, colname, JS_NewString(ctx, text));
   1977             break;
   1978         }
   1979         default:
   1980             JS_ThrowInternalError(ctx, "unexpected type from DB");
   1981             return -1;
   1982         }
   1983     }
   1984     return 0;
   1985 }
   1986 
   1987 
   1988 static JSValue js_sqlite3_stmt_get_all(JSContext *ctx, JSValue this_val,
   1989                                               int argc, JSValueConst *argv)
   1990 {
   1991     JSValue ret_val = JS_UNDEFINED;
   1992     JSValue stmt_handle = argv[0];
   1993     sqlite3_stmt *stmt;
   1994     sqlite3 *db;
   1995     int sqlret;
   1996     JSValue rows_array = JS_UNDEFINED;
   1997 
   1998     stmt = JS_GetOpaque(stmt_handle, js_sqlite3_statement_class_id);
   1999     if (!stmt) {
   2000         ret_val = JS_ThrowTypeError(ctx, "invalid sqlite3 database handle");
   2001         goto done;
   2002     }
   2003     db = sqlite3_db_handle(stmt);
   2004     sqlret = sqlite3_reset(stmt);
   2005     if (SQLITE_OK != sqlret) {
   2006         fprintf(stderr, "sqlite3_reset failed (in stmt_get_all): %s\n", sqlite3_errmsg(db));
   2007         ret_val = JS_ThrowTypeError(ctx, "failed to reset");
   2008         goto done;
   2009     }
   2010     sqlret = sqlite3_clear_bindings(stmt);
   2011     if (SQLITE_OK != sqlret) {
   2012         ret_val = JS_ThrowTypeError(ctx, "failed to clear bindings");
   2013         goto done;
   2014     }
   2015     if (argc > 1) {
   2016         if (0 != bind_from_object(ctx, stmt, argv[1])) {
   2017             ret_val = JS_EXCEPTION;
   2018             goto done;
   2019         }
   2020     }
   2021     rows_array = JS_NewArray(ctx);
   2022     while (1) {
   2023         sqlret = sqlite3_step(stmt);
   2024         switch (sqlret) {
   2025         case SQLITE_ROW: {
   2026             JSValue row_obj = JS_NewObject(ctx);
   2027             if (0 != extract_result_row(ctx, stmt, row_obj)) {
   2028                 goto fail;
   2029             }
   2030             qjs_array_append_new(ctx, rows_array, row_obj);
   2031             break;
   2032         }
   2033         case SQLITE_DONE: {
   2034             sqlret = sqlite3_reset(stmt);
   2035             if (SQLITE_OK != sqlret) {
   2036                 fprintf(stderr, "sqlite3_reset failed (in stmt_get_all after SQLITE_DONE): %s\n", sqlite3_errmsg(db));
   2037                 ret_val = JS_ThrowTypeError(ctx, "failed to reset");
   2038             } else {
   2039                 ret_val = JS_DupValue(ctx, rows_array);
   2040             }
   2041             goto done;
   2042         }
   2043         default:
   2044             ret_val = throw_sqlite3_error(ctx, db);
   2045             sqlite3_reset(stmt);
   2046             goto done;
   2047         }
   2048     }
   2049 done:
   2050     JS_FreeValue(ctx, rows_array);
   2051     return ret_val;
   2052 fail:
   2053     ret_val = JS_EXCEPTION;
   2054     goto done;
   2055 }
   2056 
   2057 static JSValue js_sqlite3_stmt_get_first(JSContext *ctx, JSValue this_val,
   2058                                               int argc, JSValueConst *argv)
   2059 {
   2060   JSValue ret_val = JS_UNDEFINED;
   2061     JSValue stmt_handle = argv[0];
   2062     sqlite3_stmt *stmt;
   2063     sqlite3 *db;
   2064     int sqlret;
   2065 
   2066     stmt = JS_GetOpaque(stmt_handle, js_sqlite3_statement_class_id);
   2067     if (!stmt) {
   2068         ret_val = JS_ThrowTypeError(ctx, "invalid sqlite3 database handle");
   2069         goto done;
   2070     }
   2071     db = sqlite3_db_handle(stmt);
   2072     sqlret = sqlite3_reset(stmt);
   2073     if (SQLITE_OK != sqlret) {
   2074         fprintf(stderr, "sqlite3_reset failed (in stmt_get_first): %s\n", sqlite3_errmsg(db));
   2075         ret_val = JS_ThrowTypeError(ctx, "failed to reset");
   2076         goto done;
   2077     }
   2078     sqlret = sqlite3_clear_bindings(stmt);
   2079     if (SQLITE_OK != sqlret) {
   2080         ret_val = JS_ThrowTypeError(ctx, "failed to clear bindings");
   2081         goto done;
   2082     }
   2083     if (argc > 1) {
   2084         if (0 != bind_from_object(ctx, stmt, argv[1])) {
   2085             ret_val = JS_EXCEPTION;
   2086             goto done;
   2087         }
   2088     }
   2089     while (1) {
   2090         sqlret = sqlite3_step(stmt);
   2091         switch (sqlret) {
   2092         case SQLITE_ROW: {
   2093             JSValue row_obj = JS_NewObject(ctx);
   2094             if (0 != extract_result_row(ctx, stmt, row_obj)) {
   2095                 goto fail;
   2096             }
   2097             ret_val = row_obj;
   2098             goto done;
   2099         }
   2100         case SQLITE_DONE: {
   2101             ret_val = JS_UNDEFINED;
   2102             goto done;
   2103         }
   2104         default:
   2105             ret_val = throw_sqlite3_error(ctx, db);
   2106             goto done;
   2107         }
   2108     }
   2109 reset:
   2110     sqlret = sqlite3_reset(stmt);
   2111     if (SQLITE_OK != sqlret) {
   2112         fprintf(stderr, "sqlite3_reset failed (in stmt_get_first): %s\n", sqlite3_errmsg(db));
   2113         JS_FreeValue(ctx, ret_val);
   2114         ret_val = JS_ThrowTypeError(ctx, "failed to reset");
   2115     }
   2116 done:
   2117     return ret_val;
   2118 fail:
   2119     ret_val = JS_EXCEPTION;
   2120     goto done;
   2121 }
   2122 
   2123 
   2124 static const JSCFunctionListEntry tart_talercrypto_funcs[] = {
   2125     JS_CFUNC_DEF("structuredClone", 1, js_structured_clone),
   2126     JS_CFUNC_DEF("encodeUtf8", 1, js_encode_utf8),
   2127     JS_CFUNC_DEF("decodeUtf8", 1, js_decode_utf8),
   2128     JS_CFUNC_DEF("randomBytes", 1, js_random_bytes),
   2129     JS_CFUNC_DEF("encodeCrock", 1, js_talercrypto_encode_crock),
   2130     JS_CFUNC_DEF("decodeCrock", 1, js_talercrypto_decode_crock),
   2131     JS_CFUNC_DEF("hash", 1, js_talercrypto_hash),
   2132     JS_CFUNC_DEF("hashStateInit", 0, js_talercrypto_hash_state_init),
   2133     JS_CFUNC_DEF("hashStateUpdate", 2, js_talercrypto_hash_state_update),
   2134     JS_CFUNC_DEF("hashStateFinish", 1, js_talercrypto_hash_state_finish),
   2135     JS_CFUNC_DEF("hashArgon2id", 5, js_talercrypto_hash_argon2id),
   2136     JS_CFUNC_DEF("eddsaGetPublic", 1, js_talercrypto_eddsa_key_get_public),
   2137     JS_CFUNC_DEF("ecdheGetPublic", 1, js_talercrypto_ecdhe_key_get_public),
   2138     JS_CFUNC_DEF("eddsaSign", 2, js_talercrypto_eddsa_sign),
   2139     JS_CFUNC_DEF("eddsaVerify", 3, js_talercrypto_eddsa_verify),
   2140     JS_CFUNC_DEF("kdf", 3, js_talercrypto_kdf),
   2141     JS_CFUNC_DEF("keyExchangeEcdhEddsa", 2, js_talercrypto_kx_ecdh_eddsa),
   2142     JS_CFUNC_DEF("keyExchangeEddsaEcdh", 2, js_talercrypto_kx_eddsa_ecdh),
   2143     JS_CFUNC_DEF("rsaBlind", 3, js_talercrypto_rsa_blind),
   2144     JS_CFUNC_DEF("rsaUnblind", 3, js_talercrypto_rsa_unblind),
   2145     JS_CFUNC_DEF("rsaVerify", 3, js_talercrypto_rsa_verify),
   2146     JS_CFUNC_DEF("sqlite3Open", 1, js_sqlite3_open),
   2147     JS_CFUNC_DEF("sqlite3Close", 1, js_sqlite3_close),
   2148     JS_CFUNC_DEF("sqlite3Prepare", 2, js_sqlite3_prepare),
   2149     JS_CFUNC_DEF("sqlite3Finalize", 1, js_sqlite3_finalize),
   2150     JS_CFUNC_DEF("sqlite3Exec", 2, js_sqlite3_exec),
   2151     JS_CFUNC_DEF("sqlite3StmtRun", 2, js_sqlite3_stmt_run),
   2152     JS_CFUNC_DEF("sqlite3StmtGetFirst", 2, js_sqlite3_stmt_get_first),
   2153     JS_CFUNC_DEF("sqlite3StmtGetAll", 2, js_sqlite3_stmt_get_all),
   2154 };
   2155 
   2156 static int tart_talercrypto_init(JSContext *ctx, JSModuleDef *m)
   2157 {    
   2158     /* create the HashState class */
   2159     JS_NewClassID(&js_hash_state_class_id);
   2160     JS_NewClass(JS_GetRuntime(ctx), js_hash_state_class_id, &js_hash_state_class);
   2161 
   2162     /* create the Sqlite3Database class*/
   2163     JS_NewClassID(&js_sqlite3_database_class_id);
   2164     JS_NewClass(JS_GetRuntime(ctx), js_sqlite3_database_class_id, &js_sqlite3_database_class);
   2165 
   2166     /* create the Sqlite3Statement class*/
   2167     JS_NewClassID(&js_sqlite3_statement_class_id);
   2168     JS_NewClass(JS_GetRuntime(ctx), js_sqlite3_statement_class_id, &js_sqlite3_statement_class);
   2169 
   2170     return JS_SetModuleExportList(ctx, m, tart_talercrypto_funcs,
   2171                                   countof(tart_talercrypto_funcs));
   2172 }
   2173 
   2174 JSModuleDef *tart_init_module_talercrypto(JSContext *ctx, const char *module_name)
   2175 {
   2176     JSModuleDef *m;
   2177     m = JS_NewCModule(ctx, module_name, tart_talercrypto_init);
   2178     if (!m) {
   2179         return NULL;
   2180     }
   2181     JS_AddModuleExportList(ctx, m, tart_talercrypto_funcs,
   2182                            countof(tart_talercrypto_funcs));
   2183     return m;
   2184 }