quickjs-tart

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

tart_module.c (75198B)


      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 #include <pthread.h>
     30 
     31 #include <arpa/inet.h>
     32 
     33 #if defined(__APPLE__)
     34 #include <sqlite3.h>
     35 #else
     36 #include "sqlite3/sqlite3.h"
     37 #endif
     38 
     39 static JSValue make_js_ta_copy(JSContext *ctx, uint8_t *data, size_t size);
     40 
     41 #define TART_MAX_RANDOM_BYTES (64U * 1024U * 1024U)
     42 #define TART_MAX_ARGON2_OUTPUT (64U * 1024U)
     43 #define TART_MAX_RSA_MODULUS_BYTES 1024U
     44 #define TART_MAX_RSA_EXPONENT_BYTES 8U
     45 
     46 /* Increment when the JavaScript-facing native API gains new semantics. */
     47 #define TART_API_VERSION 1
     48 
     49 static JSValue js_encode_utf8(JSContext *ctx, JSValueConst this_val,
     50                               int argc, JSValueConst *argv)
     51 {
     52     const char *str;
     53     size_t len;
     54     JSValue buf;
     55     str = JS_ToCStringLen2(ctx, &len, argv[0], FALSE);
     56     if (!str) {
     57         return JS_EXCEPTION;
     58     }
     59     // FIXME: Don't copy buffer but pass destructor function
     60     buf = JS_NewArrayBufferCopy(ctx, (const uint8_t*) str, len);
     61     JS_FreeCString(ctx, str);
     62     return buf;
     63 }
     64 
     65 static JSValue js_crash_for_debug(JSContext *ctx, JSValueConst this_val,
     66                                   int argc, JSValueConst *argv)
     67 {
     68   abort();
     69   return JS_EXCEPTION;
     70 }
     71 
     72 static JSValue js_random_bytes(JSContext *ctx, JSValueConst this_val,
     73                                int argc, JSValueConst *argv)
     74 {
     75     uint32_t nbytes;
     76     uint8_t *randbuf = NULL;
     77     JSValue buf = JS_EXCEPTION;
     78 
     79     if (0 != JS_ToUint32(ctx, &nbytes, argv[0])) {
     80         return JS_EXCEPTION;
     81     }
     82     if (nbytes > TART_MAX_RANDOM_BYTES) {
     83         return JS_ThrowRangeError(ctx, "random byte request is too large");
     84     }
     85     if (nbytes != 0) {
     86         randbuf = js_malloc(ctx, nbytes);
     87         if (!randbuf) {
     88             return JS_EXCEPTION;
     89         }
     90         randombytes_buf(randbuf, nbytes);
     91     }
     92     buf = JS_NewArrayBufferCopy(ctx, randbuf, nbytes);
     93     if (randbuf) {
     94         sodium_memzero(randbuf, nbytes);
     95         js_free(ctx, randbuf);
     96     }
     97     return buf;
     98 }
     99 
    100 /**
    101  * Get the decoded value corresponding to a character according to Crockford
    102  * Base32 encoding.
    103  *
    104  * @param a a character
    105  * @return corresponding numeric value
    106  */
    107 static int
    108 getValue__ (unsigned char a)
    109 {
    110     unsigned int dec;
    111 
    112     switch (a)
    113     {
    114     case 'O':
    115     case 'o':
    116         a = '0';
    117         break;
    118 
    119     case 'i':
    120     case 'I':
    121     case 'l':
    122     case 'L':
    123         a = '1';
    124         break;
    125 
    126     /* also consider U to be V */
    127     case 'u':
    128     case 'U':
    129         a = 'V';
    130         break;
    131 
    132     default:
    133         break;
    134     }
    135     if ((a >= '0') && (a <= '9'))
    136         return a - '0';
    137     if ((a >= 'a') && (a <= 'z'))
    138         a = toupper (a);
    139     /* return (a - 'a' + 10); */
    140     dec = 0;
    141     if ((a >= 'A') && (a <= 'Z'))
    142     {
    143         if ('I' < a)
    144             dec++;
    145         if ('L' < a)
    146             dec++;
    147         if ('O' < a)
    148             dec++;
    149         if ('U' < a)
    150             dec++;
    151         return(a - 'A' + 10 - dec);
    152     }
    153     return -1;
    154 }
    155 
    156 static JSValue js_talercrypto_encode_crock(JSContext *ctx, JSValue this_val,
    157                                            int argc, JSValueConst *argv)
    158 {
    159     size_t size;
    160     uint8_t *buf;
    161     uint8_t *out = NULL;
    162     size_t out_size;
    163     // 32 characters for encoding
    164     static char *encTable__ = "0123456789ABCDEFGHJKMNPQRSTVWXYZ";
    165     unsigned int wpos;
    166     unsigned int rpos;
    167     unsigned int bits;
    168     unsigned int vbit;
    169     const unsigned char *udata;
    170     JSValue ret_val;
    171 
    172     ret_val = JS_UNDEFINED;
    173 
    174     buf = JS_GetArrayBuffer(ctx, &size, argv[0]);
    175 
    176     if (!buf) {
    177         goto exception;
    178     }
    179 
    180     if (size > (SIZE_MAX - 4) / 8) {
    181         return JS_ThrowRangeError(ctx, "input is too large");
    182     }
    183     out_size = size * 8;
    184 
    185     if (out_size % 5 > 0)
    186         out_size += 5 - out_size % 5;
    187     out_size /= 5;
    188 
    189     out = malloc (out_size + 1);
    190     if (!out) {
    191         JS_ThrowOutOfMemory(ctx);
    192         goto exception;
    193     }
    194     memset (out, 0, out_size + 1);
    195 
    196     udata = buf;
    197     if (out_size < (size * 8 + 4) / 5) {
    198         goto exception;
    199     }
    200     vbit = 0;
    201     wpos = 0;
    202     rpos = 0;
    203     bits = 0;
    204     while ((rpos < size) || (vbit > 0))
    205     {
    206         if ((rpos < size) && (vbit < 5))
    207         {
    208             /* eat 8 more bits */
    209             bits = (bits << 8) | udata[rpos++];     
    210             vbit += 8;
    211         }
    212         if (vbit < 5)
    213         {
    214             bits <<= (5 - vbit);     /* zero-padding */
    215             assert (vbit == ((size * 8) % 5));
    216             vbit = 5;
    217         }
    218         if (wpos >= out_size)
    219         {
    220             goto exception;
    221         }
    222         out[wpos++] = encTable__[(bits >> (vbit - 5)) & 31];
    223         vbit -= 5;
    224     }
    225     assert (0 == vbit);
    226     if (wpos < out_size) {
    227         out[wpos] = '\0';
    228     }
    229 
    230     ret_val = JS_NewString(ctx, (char *) out);
    231 
    232 done:
    233     if (NULL != out) {
    234         free(out);
    235     }
    236     return ret_val;
    237 exception:
    238     ret_val = JS_EXCEPTION;
    239     goto done;
    240 }
    241 
    242 static JSValue js_talercrypto_decode_crock(JSContext *ctx, JSValue this_val,
    243                                            int argc, JSValueConst *argv)
    244 {
    245     size_t rpos;
    246     size_t wpos;
    247     unsigned int bits;
    248     unsigned int vbit;
    249     int ret;
    250     int shift;
    251     size_t enclen;
    252     size_t encoded_len;
    253     const char *enc;
    254     JSValue ret_val = JS_UNDEFINED;
    255     unsigned char *uout = NULL;
    256     size_t out_size;
    257     JSValue abuf;
    258 
    259     enc = JS_ToCStringLen2(ctx, &enclen, argv[0], FALSE);
    260     if (!enc) {
    261         goto exception;
    262     }
    263 
    264     if (enclen == 0) {
    265         ret_val = make_js_ta_copy(ctx, NULL, 0);
    266         goto done;
    267     }
    268     if (enclen > SIZE_MAX / 5) {
    269         JS_ThrowRangeError(ctx, "encoded input is too large");
    270         goto exception;
    271     }
    272     out_size = (enclen * 5) / 8;
    273     encoded_len = out_size * 8;
    274     uout = malloc(out_size);
    275     if (out_size != 0 && !uout) {
    276         JS_ThrowOutOfMemory(ctx);
    277         goto exception;
    278     }
    279     wpos = out_size;
    280     rpos = enclen;
    281     if ((encoded_len % 5) > 0)
    282     {
    283         vbit = encoded_len % 5;   /* padding! */
    284         shift = 5 - vbit;
    285         bits = (ret = getValue__ (enc[--rpos])) >> shift;
    286         if (ret < 0 || (ret & ((1U << shift) - 1)) != 0) {
    287             JS_ThrowTypeError(ctx, "invalid padding bits in encoding");
    288             goto exception;
    289         }
    290     }
    291     else
    292     {
    293         vbit = 5;
    294         shift = 0;
    295         bits = (ret = getValue__ (enc[--rpos]));
    296     }
    297     if ((encoded_len + shift) / 5 != enclen) {
    298         JS_ThrowTypeError(ctx, "wrong encoded length");
    299         goto exception;
    300     }
    301 
    302     if (-1 == ret) {
    303         JS_ThrowTypeError(ctx, "invalid character in encoding");
    304         goto exception;
    305     }
    306     while (wpos > 0)
    307     {
    308         if (0 == rpos)
    309         {
    310             goto exception;
    311         }
    312         bits = ((ret = getValue__ (enc[--rpos])) << vbit) | bits;
    313         if (-1 == ret) {
    314             JS_ThrowTypeError(ctx, "invalid character in encoding");
    315             goto exception;
    316         }
    317         vbit += 5;
    318         if (vbit >= 8)
    319         {
    320             uout[--wpos] = (unsigned char) bits;
    321             bits >>= 8;
    322             vbit -= 8;
    323         }
    324     }
    325     if ((0 != rpos) || (0 != vbit)) {
    326         JS_ThrowTypeError(ctx, "rpos or vbit not zero");
    327         goto exception;
    328     }
    329     abuf = JS_NewArrayBufferCopy(ctx, uout, out_size);
    330     if (JS_IsException(abuf)) {
    331         goto exception;
    332     }
    333     ret_val = JS_NewTypedArraySimple(ctx, abuf, 1);
    334 done:
    335     JS_FreeCString(ctx, enc);
    336     if (uout) {
    337         free(uout);
    338     }
    339     return ret_val;
    340 exception:
    341     ret_val = JS_EXCEPTION;
    342     goto done;
    343 }
    344 
    345 uint8_t *expect_fixed_buffer(JSContext *ctx,
    346                              JSValue val, size_t len,
    347                              const char *msg)
    348 {
    349     uint8_t *buf;
    350     size_t sz;
    351 
    352     buf = JS_GetArrayBuffer(ctx, &sz, val);
    353     if (!buf) {
    354         return NULL;
    355     }
    356     if (sz != len) {
    357         JS_ThrowTypeError(ctx, "invalid length for %s", msg);
    358         return NULL;
    359     }
    360     return buf;
    361 }
    362 
    363 int
    364 expect_mpi(JSContext *ctx,
    365            JSValue val,
    366            const char *msg,
    367            mbedtls_mpi *ret_mpi)
    368 {
    369     uint8_t *buf;
    370     size_t sz;
    371 
    372     buf = JS_GetArrayBuffer(ctx, &sz, val);
    373     if (!buf) {
    374         return -1;
    375     }
    376     if (0 != mbedtls_mpi_read_binary(ret_mpi, buf, sz)) {
    377         return -1;
    378     }
    379     return 0;
    380 }
    381 
    382 #define CHECK(x) do { if (!(x)) { abort(); } } while (0)
    383 
    384 typedef struct {
    385     mbedtls_mpi N;
    386     mbedtls_mpi e;
    387 } RsaPub;
    388 
    389 typedef uint8_t BlindingKeySecret[32];
    390 typedef uint8_t HashCode[64];
    391 
    392 int
    393 rsa_public_key_decode(RsaPub *pkey, uint8_t *inbuf, size_t inbuf_len)
    394 {
    395     size_t sz;
    396     uint8_t *p; /* read pointer */
    397     size_t mod_len;
    398     size_t exp_len;
    399     int ret;
    400 
    401     CHECK(NULL != pkey);
    402     if (inbuf_len < 4) {
    403         ret = -1;
    404         goto cleanup;
    405     }
    406     p = inbuf;
    407     uint16_t encoded_len;
    408 
    409     memcpy(&encoded_len, p, sizeof encoded_len);
    410     mod_len = ntohs(encoded_len);
    411     p += sizeof(uint16_t);
    412     memcpy(&encoded_len, p, sizeof encoded_len);
    413     exp_len = ntohs(encoded_len);
    414     sz = 4 + mod_len + exp_len;
    415     if (sz != inbuf_len ||
    416         mod_len < 128 || mod_len > TART_MAX_RSA_MODULUS_BYTES ||
    417         exp_len == 0 || exp_len > TART_MAX_RSA_EXPONENT_BYTES) {
    418         ret = -1;
    419         goto cleanup;
    420     }
    421     p += sizeof(uint16_t);
    422     MBEDTLS_MPI_CHK(mbedtls_mpi_read_binary(&pkey->N, p, mod_len));
    423     p += mod_len;
    424     MBEDTLS_MPI_CHK(mbedtls_mpi_read_binary(&pkey->e, p, exp_len));
    425     if (mbedtls_mpi_cmp_int(&pkey->N, 3) <= 0 ||
    426         mbedtls_mpi_get_bit(&pkey->N, 0) == 0 ||
    427         mbedtls_mpi_cmp_int(&pkey->e, 3) < 0 ||
    428         mbedtls_mpi_get_bit(&pkey->e, 0) == 0 ||
    429         mbedtls_mpi_cmp_mpi(&pkey->e, &pkey->N) >= 0) {
    430         ret = -1;
    431         goto cleanup;
    432     }
    433 
    434 cleanup:
    435     if (ret != 0) {
    436         mbedtls_mpi_free(&pkey->N);
    437         mbedtls_mpi_free(&pkey->e);
    438     }
    439     return ret;
    440 }
    441 
    442 int
    443 expect_rsa_pub(JSContext *ctx,
    444                JSValue val,
    445                const char *msg,
    446                RsaPub *ret_rsa_pub)
    447 {
    448     uint8_t *rsa_enc;
    449     size_t rsa_enc_len;
    450     int ret = -1;
    451 
    452     rsa_enc = JS_GetArrayBuffer(ctx, &rsa_enc_len, val);
    453     if (!rsa_enc) {
    454         goto cleanup;
    455     }
    456     if (0 != rsa_public_key_decode(ret_rsa_pub, rsa_enc, rsa_enc_len)) {
    457         JS_ThrowTypeError(ctx, "rsa pubkey");
    458         goto cleanup;
    459     }
    460     ret = 0;
    461 cleanup:
    462     return ret;
    463 }
    464 
    465 #define REQUIRE(cond, _label) do { if (!(cond)) { goto _label; } } while (0)
    466 
    467 
    468 static JSValue make_js_ta_copy(JSContext *ctx, uint8_t *data, size_t size)
    469 {
    470     JSValue array_buf;
    471 
    472     array_buf = JS_NewArrayBufferCopy(ctx, data, size);
    473     if (JS_IsException(array_buf)) {
    474         return JS_EXCEPTION;
    475     }
    476     return JS_NewTypedArraySimple(ctx, array_buf, 1);
    477 }
    478 
    479 /**
    480  * Make a JS typed array from an mbedtls MPI.
    481 */
    482 static JSValue make_js_ta_mpi(JSContext *ctx, const mbedtls_mpi *v)
    483 {
    484     JSValue array_buf;
    485     size_t sz;
    486     uint8_t *buf = NULL;
    487     JSValue ret_val;
    488 
    489     sz = mbedtls_mpi_size(v);
    490     buf = malloc(sz);
    491     if (!buf) {
    492         ret_val = JS_EXCEPTION;
    493         goto cleanup;
    494     }
    495 
    496     if (0 != mbedtls_mpi_write_binary(v, buf, sz)) {
    497         ret_val = JS_EXCEPTION;
    498         goto cleanup;
    499     }
    500 
    501     // FIXME(#perf): Don't copy
    502     array_buf = JS_NewArrayBufferCopy(ctx, buf, sz);
    503     if (JS_IsException(array_buf)) {
    504         ret_val = JS_EXCEPTION;
    505         goto cleanup;
    506     }
    507     ret_val = JS_NewTypedArraySimple(ctx, array_buf, 1);
    508 cleanup:
    509     if (buf) {
    510         free(buf);
    511     }
    512     return ret_val;
    513 }
    514 
    515 static JSValue js_talercrypto_hash(JSContext *ctx, JSValue this_val,
    516                                    int argc, JSValueConst *argv)
    517 {
    518     size_t size;
    519     uint8_t *buf;
    520     unsigned char h[crypto_hash_BYTES];
    521 
    522     buf = JS_GetArrayBuffer(ctx, &size, argv[0]);
    523     if (!buf) {
    524         return JS_EXCEPTION;
    525     }
    526     crypto_hash_sha512(h, buf, size);
    527 
    528     return make_js_ta_copy(ctx, h, crypto_hash_BYTES);
    529 }
    530 
    531 static JSValue js_talercrypto_hash_argon2id(JSContext *ctx, JSValue this_val,
    532                                             int argc, JSValueConst *argv)
    533 {
    534     size_t pw_len;
    535     size_t salt_len;
    536     uint32_t iters;
    537     uint32_t mem_size;
    538     uint32_t hash_len;
    539     uint8_t *pw;
    540     uint8_t *salt;
    541     uint8_t *hash = NULL;
    542 
    543     JSValue ret_val;
    544 
    545     // password: Uint8Array
    546     pw = JS_GetArrayBuffer(ctx, &pw_len, argv[0]);
    547     if (!pw) {
    548         goto exception;
    549     }
    550 
    551     // salt: Uint8Array
    552     salt = JS_GetArrayBuffer(ctx, &salt_len, argv[1]);
    553     if (!salt) {
    554         goto exception;
    555     }
    556     if (salt_len != crypto_pwhash_SALTBYTES) {
    557         JS_ThrowTypeError(ctx, "invalid salt size");
    558         goto exception;
    559     }
    560 
    561     // iterations: number
    562     if (0 != JS_ToUint32(ctx, &iters, argv[2])) {
    563         goto exception;
    564     }
    565 
    566     // memorySize: number (kibibytes)
    567     if (0 != JS_ToUint32(ctx, &mem_size, argv[3])) {
    568         goto exception;
    569     }
    570 
    571     // hashLength: number
    572     if (0 != JS_ToUint32(ctx, &hash_len, argv[4])) {
    573         goto exception;
    574     }
    575 
    576     if (iters < crypto_pwhash_OPSLIMIT_MIN ||
    577         iters > crypto_pwhash_OPSLIMIT_MAX ||
    578         iters > crypto_pwhash_OPSLIMIT_MODERATE) {
    579         JS_ThrowRangeError(ctx, "iterations out of range");
    580         goto exception;
    581     }
    582     if (hash_len < crypto_pwhash_BYTES_MIN ||
    583         hash_len > crypto_pwhash_BYTES_MAX ||
    584         hash_len > TART_MAX_ARGON2_OUTPUT) {
    585         JS_ThrowRangeError(ctx, "hash length out of range");
    586         goto exception;
    587     }
    588 
    589     // Check for overflow when converting memory size to bytes
    590     if (((unsigned long long)mem_size * 1024) > UINT32_MAX) {
    591         JS_ThrowTypeError(ctx, "mem_size too large");
    592         goto exception;
    593     }
    594 
    595     if ((size_t) mem_size * 1024 < crypto_pwhash_MEMLIMIT_MIN ||
    596         (size_t) mem_size * 1024 > crypto_pwhash_MEMLIMIT_MAX ||
    597         (size_t) mem_size * 1024 > crypto_pwhash_MEMLIMIT_MODERATE) {
    598         JS_ThrowRangeError(ctx, "memory size out of range");
    599         goto exception;
    600     }
    601 
    602     hash = malloc(hash_len);
    603     if (NULL == hash) {
    604       JS_ThrowOutOfMemory(ctx);
    605       goto exception;
    606     }
    607 
    608     if (crypto_pwhash(hash,
    609                       hash_len,
    610                       (const char*) pw,
    611                       pw_len,
    612                       salt,
    613                       iters,
    614                       mem_size * 1024,
    615                       crypto_pwhash_ALG_ARGON2ID13) != 0) {
    616         JS_ThrowInternalError(ctx, "crypto_pwhash() call failed");
    617         goto exception;
    618     }
    619     ret_val = make_js_ta_copy(ctx, hash, hash_len);
    620 done:
    621     if (NULL != hash) {
    622         sodium_memzero(hash, hash_len);
    623         free(hash);
    624     }
    625     return ret_val;
    626  exception:
    627     ret_val = JS_EXCEPTION;
    628     goto done;
    629 }
    630 
    631 static JSValue js_talercrypto_eddsa_key_get_public(JSContext *ctx, JSValue this_val,
    632                                                    int argc, JSValueConst *argv)
    633 {
    634     JSValue ret;
    635     uint8_t *buf;
    636     unsigned char pk[crypto_sign_PUBLICKEYBYTES];
    637     unsigned char sk[crypto_sign_SECRETKEYBYTES];
    638 
    639     buf = expect_fixed_buffer(ctx, argv[0], crypto_sign_SEEDBYTES,
    640                               "eddsa private key seed");
    641     
    642     if (!buf) {
    643         goto exception;
    644     }
    645 
    646     crypto_sign_seed_keypair(pk, sk, buf);
    647 
    648     ret = make_js_ta_copy(ctx, pk, crypto_sign_PUBLICKEYBYTES);
    649 done:
    650     sodium_memzero(sk, sizeof sk);
    651     return ret;
    652 exception:
    653     ret = JS_EXCEPTION;
    654     goto done;
    655 }
    656 
    657 static JSValue js_talercrypto_ecdhe_key_get_public(JSContext *ctx, JSValue this_val,
    658                                                    int argc, JSValueConst *argv)
    659 {
    660     JSValue ret;
    661     uint8_t *buf;
    662     unsigned char pk[crypto_scalarmult_BYTES];
    663 
    664     buf = expect_fixed_buffer(ctx, argv[0], crypto_sign_SEEDBYTES, "ecdh private key seed");
    665     
    666     if (!buf) {
    667         goto exception;
    668     }
    669 
    670     if (0 != crypto_scalarmult_base(pk, buf)) {
    671         goto exception;
    672     }
    673 
    674     ret = make_js_ta_copy(ctx, pk, crypto_sign_PUBLICKEYBYTES);
    675 done:
    676     buf = NULL;
    677     return ret;
    678 exception:
    679     ret = JS_EXCEPTION;
    680     goto done;
    681 }
    682 
    683 /**
    684  * (msg, priv) => sig
    685  */
    686 static JSValue js_talercrypto_eddsa_sign(JSContext *ctx, JSValue this_val,
    687                                          int argc, JSValueConst *argv)
    688 {
    689     unsigned char *seed;
    690     size_t seed_size;
    691     unsigned char *data;
    692     size_t data_size;
    693     unsigned char sk[crypto_sign_SECRETKEYBYTES];
    694     unsigned char pk[crypto_sign_PUBLICKEYBYTES];
    695     unsigned char sig[64];
    696     int res;
    697     JSValue ret = JS_EXCEPTION;
    698 
    699     data = JS_GetArrayBuffer(ctx, &data_size, argv[0]);
    700     if (!data) {
    701         goto done;
    702     }
    703 
    704     seed = JS_GetArrayBuffer(ctx, &seed_size, argv[1]);
    705     if (!seed) {
    706         goto done;
    707     }
    708     if (seed_size != 32) {
    709         ret = JS_ThrowTypeError(ctx, "invalid private key seed size");
    710         goto done;
    711     }
    712 
    713     if (0 != crypto_sign_seed_keypair(pk, sk, seed)) {
    714         goto done;
    715     }
    716 
    717     res = crypto_sign_detached((uint8_t *)sig,
    718                                NULL,
    719                                (uint8_t *)data,
    720                                data_size,
    721                                sk);
    722     if (res != 0) {
    723         goto done;
    724     }
    725     ret = make_js_ta_copy(ctx, sig, 64);
    726 done:
    727     sodium_memzero(sk, sizeof sk);
    728     return ret;
    729 }
    730 
    731 /**
    732  * (msg, sig, pub) -> bool
    733  */
    734 static JSValue js_talercrypto_eddsa_verify(JSContext *ctx, JSValue this_val,
    735                                            int argc, JSValueConst *argv)
    736 {
    737     unsigned char *msg;
    738     size_t msg_size;
    739     unsigned char *sig;
    740     size_t sig_size;
    741     unsigned char *pub;
    742     size_t pub_size;
    743     int res;
    744 
    745     msg = JS_GetArrayBuffer(ctx, &msg_size, argv[0]);
    746     if (!msg) {
    747         return JS_EXCEPTION;
    748     }
    749     sig = JS_GetArrayBuffer(ctx, &sig_size, argv[1]);
    750     if (!sig) {
    751         return JS_EXCEPTION;
    752     }
    753     if (sig_size != 64) {
    754         return JS_ThrowTypeError(ctx, "invalid signature size");
    755     }
    756     pub = JS_GetArrayBuffer(ctx, &pub_size, argv[2]);
    757     if (!pub) {
    758         return JS_EXCEPTION;
    759     }
    760     if (pub_size != 32) {
    761         return JS_ThrowTypeError(ctx, "invalid public key size");
    762     }
    763 
    764     res = crypto_sign_verify_detached (sig, msg, msg_size, pub);
    765     return (res == 0) ? JS_TRUE : JS_FALSE;
    766 }
    767 
    768 /**
    769  * Returns 0 on success.
    770  */
    771 static int
    772 kdf(void *okm, size_t okm_len,
    773     const void *ikm, size_t ikm_len,
    774     const void *salt, size_t salt_len,
    775     const void *info, size_t info_len)
    776 {
    777     const mbedtls_md_info_t *md_extract;
    778     const mbedtls_md_info_t *md_expand;
    779     int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
    780     unsigned char prk[MBEDTLS_MD_MAX_SIZE];
    781 
    782     md_extract = mbedtls_md_info_from_type(MBEDTLS_MD_SHA512);
    783     md_expand = mbedtls_md_info_from_type(MBEDTLS_MD_SHA256);
    784     if (NULL == md_extract) {
    785         return -1;
    786     }
    787     if (NULL == md_expand) {
    788         return -1;
    789     }
    790 
    791     ret = mbedtls_hkdf_extract(md_extract, salt, salt_len, ikm, ikm_len, prk);
    792 
    793     if (ret != 0) {
    794         return ret;
    795     }
    796 
    797     ret = mbedtls_hkdf_expand(md_expand, prk, mbedtls_md_get_size(md_extract),
    798                               info, info_len, okm, okm_len);
    799     return ret;
    800 }
    801 
    802 /**
    803  * (outLen, ikm, salt?, info?) -> output
    804  */
    805 static JSValue js_talercrypto_kdf(JSContext *ctx, JSValue this_val,
    806                                   int argc, JSValueConst *argv)
    807 {
    808     size_t salt_len;
    809     size_t ikm_len;
    810     size_t info_len;
    811     size_t okm_len;
    812     uint8_t *salt;
    813     uint8_t *ikm;
    814     uint8_t *info;
    815     uint8_t *okm = NULL;
    816     uint8_t empty_okm;
    817     uint32_t out_bytes;
    818     JSValue ret_val;
    819     int ret;
    820 
    821     if (0 != JS_ToUint32(ctx, &out_bytes, argv[0])) {
    822         goto exception;
    823     }
    824     okm_len = out_bytes;
    825     if (okm_len > 255 * 32) {
    826         JS_ThrowRangeError(ctx, "HKDF output is too large");
    827         goto exception;
    828     }
    829 
    830     ikm = JS_GetArrayBuffer(ctx, &ikm_len, argv[1]);
    831     if (!ikm) {
    832         goto exception;
    833     }
    834 
    835     if (JS_IsUndefined(argv[2])) {
    836         salt = NULL;
    837         salt_len = 0;
    838     } else {
    839         salt = JS_GetArrayBuffer(ctx, &salt_len, argv[2]);
    840         if (!salt) {
    841             goto exception;
    842         }
    843     }
    844 
    845     if (JS_IsUndefined(argv[3])) {
    846         info = NULL;
    847         info_len = 0;
    848     } else {
    849         info = JS_GetArrayBuffer(ctx, &info_len, argv[3]);
    850         if (!info) {
    851             goto exception;
    852         }
    853     }
    854 
    855     if (okm_len != 0) {
    856         okm = malloc(okm_len);
    857         if (!okm) {
    858             JS_ThrowOutOfMemory(ctx);
    859             goto exception;
    860         }
    861     }
    862 
    863     ret = kdf(okm_len == 0 ? &empty_okm : okm, okm_len,
    864               ikm, ikm_len, salt, salt_len, info, info_len);
    865 
    866     if (ret != 0) {
    867         JS_ThrowInternalError(ctx, "kdf() call failed");
    868         goto exception;
    869     }
    870     ret_val = make_js_ta_copy(ctx, okm, okm_len);
    871 done:
    872     if (NULL != okm) {
    873         sodium_memzero(okm, okm_len);
    874         free(okm);
    875     }
    876     return ret_val;
    877 exception:
    878     ret_val = JS_EXCEPTION;
    879     goto done;
    880 }
    881 
    882 /**
    883  * (ecdhePriv, eddsaPub) -> keyMaterial
    884  */
    885 static JSValue js_talercrypto_kx_ecdh_eddsa(JSContext *ctx, JSValue this_val,
    886                                             int argc, JSValueConst *argv)
    887 {
    888     JSValue ret_val;
    889     uint8_t p[crypto_scalarmult_BYTES];
    890     uint8_t *ecdh_priv;
    891     uint8_t *eddsa_pub;
    892     uint8_t curve25510_pk[crypto_scalarmult_BYTES];
    893     uint8_t key_material[crypto_hash_BYTES];
    894 
    895     ecdh_priv = expect_fixed_buffer(ctx, argv[0], 32, "ecdhe priv");
    896     REQUIRE(ecdh_priv, exception);
    897 
    898     eddsa_pub = expect_fixed_buffer(ctx, argv[1], 32, "eddsa pub");
    899     REQUIRE(eddsa_pub, exception);
    900 
    901     if (0 != crypto_sign_ed25519_pk_to_curve25519(curve25510_pk, eddsa_pub)) {
    902         goto exception;
    903     }
    904     if (0 != crypto_scalarmult(p, ecdh_priv, curve25510_pk)) {
    905         goto exception;
    906     }
    907     if (0 != crypto_hash(key_material, p, 32)) {
    908         JS_ThrowTypeError(ctx, "hashing failed");
    909         goto exception;
    910     }
    911     ret_val = make_js_ta_copy(ctx, key_material, crypto_hash_BYTES);
    912 done:
    913     sodium_memzero(p, sizeof p);
    914     sodium_memzero(key_material, sizeof key_material);
    915     return ret_val;
    916 exception:
    917     ret_val = JS_EXCEPTION;
    918     goto done;
    919 }
    920 
    921 /**
    922  * (eddsaPriv, ecdhePub) -> keyMaterial
    923  */
    924 static JSValue js_talercrypto_kx_eddsa_ecdh(JSContext *ctx, JSValue this_val,
    925                                             int argc, JSValueConst *argv)
    926 {
    927     JSValue ret_val;
    928     uint8_t *priv;
    929     uint8_t *pub;
    930     uint8_t hc[crypto_hash_BYTES];
    931     uint8_t a[crypto_scalarmult_SCALARBYTES];
    932     uint8_t p[crypto_scalarmult_BYTES];
    933     uint8_t key_material[crypto_hash_BYTES];
    934 
    935     priv = expect_fixed_buffer(ctx, argv[0], 32, "eddsa priv");
    936     REQUIRE(priv, exception);
    937     pub = expect_fixed_buffer(ctx, argv[1], 32, "ecdh pub");
    938     REQUIRE(pub, exception);
    939 
    940     crypto_hash(hc, priv, 32);
    941     memcpy (a, &hc, 32);
    942     if (0 != crypto_scalarmult(p, a, pub)) {
    943         goto exception;
    944     }
    945     crypto_hash(key_material, p, crypto_scalarmult_BYTES);
    946     ret_val = make_js_ta_copy(ctx, key_material, crypto_hash_BYTES);
    947 done:
    948     sodium_memzero(hc, sizeof hc);
    949     sodium_memzero(a, sizeof a);
    950     sodium_memzero(p, sizeof p);
    951     sodium_memzero(key_material, sizeof key_material);
    952     return ret_val;
    953 exception:
    954     ret_val = JS_EXCEPTION;
    955     goto done;
    956 }
    957 
    958 static int
    959 kdf_mod_mpi(mbedtls_mpi *r,
    960             const mbedtls_mpi *n,
    961             const void *xts, size_t xts_len,
    962             const void *skm, size_t skm_len,
    963             const char *ctx)
    964 {
    965     int ret = -1;
    966     size_t nbits;
    967     uint32_t ctr;
    968     size_t ctxlen = strlen(ctx);
    969     size_t my_ctx_len = ctxlen + 2;
    970     unsigned char *my_ctx = NULL;
    971     uint8_t *buf = NULL;
    972     size_t bsize;
    973 
    974     my_ctx = malloc(my_ctx_len);
    975     if (!my_ctx) {
    976         goto cleanup;
    977     }
    978     memcpy(my_ctx, ctx, ctxlen);
    979 
    980     nbits = mbedtls_mpi_bitlen(n);
    981     if (nbits == 0) {
    982         goto cleanup;
    983     }
    984     bsize = (nbits + 7) / 8;
    985     buf = malloc(bsize);
    986     if (!buf) {
    987         goto cleanup;
    988     }
    989     for (ctr = 0; ctr <= UINT16_MAX; ctr++) {
    990         uint16_t ctr_nbo = htons((uint16_t) ctr);
    991 
    992         memcpy(my_ctx + ctxlen, &ctr_nbo, sizeof ctr_nbo);
    993         if (0 != kdf(buf, bsize,
    994                      skm, skm_len,
    995                      xts, xts_len,
    996                      my_ctx, my_ctx_len)) {
    997             goto cleanup;
    998         }
    999         if (0 != mbedtls_mpi_read_binary(r, buf, bsize)) {
   1000             goto cleanup;
   1001         }
   1002         while (1) {
   1003             size_t rlen = mbedtls_mpi_bitlen(r);
   1004             if (rlen <= nbits) {
   1005                 break;
   1006             }
   1007             if (0 != mbedtls_mpi_set_bit(r, rlen - 1, 0)) {
   1008                 goto cleanup;
   1009             }
   1010         }
   1011         /* We reject this FDH if either r > n and retry with another ctr */
   1012         if (0 > mbedtls_mpi_cmp_mpi (r, n)) {
   1013             ret = 0;
   1014             break;
   1015         }
   1016         mbedtls_mpi_free (r);
   1017         mbedtls_mpi_init (r);
   1018     }
   1019 cleanup:
   1020     if (buf) {
   1021         sodium_memzero(buf, bsize);
   1022     }
   1023     free(buf);
   1024     free(my_ctx);
   1025     return ret;
   1026 }
   1027 
   1028 
   1029 /**
   1030  * Test for malicious RSA key.
   1031  *
   1032  * Assuming n is an RSA modulous and r is generated using a call to
   1033  * GNUNET_CRYPTO_kdf_mod_mpi, if gcd(r,n) != 1 then n must be a
   1034  * malicious RSA key designed to deanomize the user.
   1035  *
   1036  * @param r KDF result
   1037  * @param n RSA modulus
   1038  * @return 0 if gcd(r,n) = 1, 1 means RSA key is malicious, negative is syserror
   1039  */
   1040 static int
   1041 rsa_gcd_validate (mbedtls_mpi *r,
   1042                   const mbedtls_mpi *n)
   1043 {
   1044     mbedtls_mpi g;
   1045     int ret;
   1046 
   1047     mbedtls_mpi_init(&g);
   1048     MBEDTLS_MPI_CHK(mbedtls_mpi_gcd(&g, r, n));
   1049 
   1050     if (mbedtls_mpi_cmp_int(&g, 1) == 0) {
   1051         ret = 0;
   1052     } else {
   1053         ret = 1;
   1054     }
   1055 
   1056 cleanup:
   1057     mbedtls_mpi_free(&g);
   1058     return ret;
   1059 }
   1060 
   1061 
   1062 int
   1063 rsa_blinding_key_derive(mbedtls_mpi *r,
   1064                         const RsaPub *pkey,
   1065                         const BlindingKeySecret *bks)
   1066 {
   1067     /* Trusts bks' randomness more */
   1068     const char *xts = "Blinding KDF extractor HMAC key";
   1069 
   1070     if (0 != kdf_mod_mpi(r,
   1071                          &pkey->N,
   1072                          xts, strlen(xts),
   1073                          bks, sizeof(*bks),
   1074                          "Blinding KDF")) {
   1075         return -1;
   1076     }
   1077 
   1078     if (0 != rsa_gcd_validate (r, &pkey->N)) {
   1079         return -1;
   1080     }
   1081 
   1082     return 0;
   1083 }
   1084 
   1085 int
   1086 rsa_public_key_encode(const RsaPub *pkey, uint8_t **outbuf, size_t *outbuf_len)
   1087 {
   1088     size_t sz;
   1089     uint8_t *buf;
   1090     uint8_t *p; /* write pointer */
   1091     size_t mod_len;
   1092     size_t exp_len;
   1093     int ret;
   1094 
   1095     *outbuf = NULL;
   1096     *outbuf_len = 0;
   1097 
   1098     mod_len = mbedtls_mpi_size(&pkey->N);
   1099     exp_len = mbedtls_mpi_size(&pkey->e);
   1100     if (mod_len > UINT16_MAX || exp_len > UINT16_MAX) {
   1101         return -1;
   1102     }
   1103     sz = 2 + 2 + exp_len + mod_len;
   1104     buf = malloc(sz);
   1105     if (!buf) {
   1106         return -1;
   1107     }
   1108 
   1109     p = buf;
   1110     uint16_t encoded_len = htons((uint16_t) mod_len);
   1111     memcpy(p, &encoded_len, sizeof encoded_len);
   1112     p += sizeof (uint16_t);
   1113     encoded_len = htons((uint16_t) exp_len);
   1114     memcpy(p, &encoded_len, sizeof encoded_len);
   1115     p += sizeof (uint16_t);
   1116     MBEDTLS_MPI_CHK(mbedtls_mpi_write_binary(&pkey->N, p, mod_len));
   1117     p += mod_len;
   1118     MBEDTLS_MPI_CHK(mbedtls_mpi_write_binary(&pkey->e, p, exp_len));
   1119 
   1120     *outbuf = buf;
   1121     *outbuf_len = sz;
   1122 
   1123 cleanup:
   1124     if (0 != ret) {
   1125         free(buf);
   1126     }
   1127     return ret;
   1128 }
   1129 
   1130 
   1131 void
   1132 rsa_public_key_init(RsaPub *pkey)
   1133 {
   1134     CHECK(NULL != pkey);
   1135     mbedtls_mpi_init(&pkey->e);
   1136     mbedtls_mpi_init(&pkey->N);
   1137 }
   1138 
   1139 void
   1140 rsa_public_key_free(RsaPub *pkey)
   1141 {
   1142     if (!pkey) {
   1143         return;
   1144     }
   1145     mbedtls_mpi_free(&pkey->e);
   1146     mbedtls_mpi_free(&pkey->N);
   1147 }
   1148 
   1149 
   1150 int
   1151 rsa_full_domain_hash (mbedtls_mpi *r, const RsaPub *pkey,
   1152                       const HashCode *hash)
   1153 {
   1154     uint8_t *xts;
   1155     size_t xts_len;
   1156 
   1157     /* We key with the public denomination key as a homage to RSA-PSS by
   1158        Mihir Bellare and Phillip Rogaway.  Doing this lowers the degree
   1159        of the hypothetical polyomial-time attack on RSA-KTI created by a
   1160        polynomial-time one-more forgary attack.  Yey seeding! */
   1161     if (0 != rsa_public_key_encode(pkey, &xts, &xts_len)) {
   1162         return -1;
   1163     }
   1164 
   1165     if (0 != kdf_mod_mpi(r,
   1166                          &pkey->N,
   1167                          xts, xts_len,
   1168                          hash, sizeof(*hash),
   1169                          "RSA-FDA FTpsW!")) {
   1170         free(xts);
   1171         return -1;
   1172     }
   1173     free(xts);
   1174     if (0 == rsa_gcd_validate (r, &pkey->N)) {
   1175         return 0;
   1176     }
   1177     return 1;
   1178 }
   1179 
   1180 static int
   1181 rsa_blind(const HashCode *hash,
   1182           const BlindingKeySecret *bks,
   1183           const RsaPub *pkey,
   1184           uint8_t **buf,
   1185           size_t *buf_size)
   1186 {
   1187     mbedtls_mpi bkey, data, r_e, data_r_e;
   1188     size_t outsize;
   1189     uint8_t *outbuf;
   1190     int ret;
   1191 
   1192     CHECK(buf != NULL);
   1193     CHECK(buf_size != NULL);
   1194 
   1195     *buf = NULL;
   1196     *buf_size = 0;
   1197 
   1198     mbedtls_mpi_init(&bkey);
   1199     mbedtls_mpi_init(&data);
   1200     mbedtls_mpi_init(&r_e);
   1201     mbedtls_mpi_init(&data_r_e);
   1202 
   1203     MBEDTLS_MPI_CHK(rsa_full_domain_hash (&data, pkey, hash));
   1204     MBEDTLS_MPI_CHK(rsa_blinding_key_derive (&bkey, pkey, bks));
   1205     MBEDTLS_MPI_CHK(mbedtls_mpi_exp_mod(&r_e, &bkey, &pkey->e, &pkey->N, NULL));
   1206     MBEDTLS_MPI_CHK(mbedtls_mpi_mul_mpi(&data_r_e, &data, &r_e));
   1207     MBEDTLS_MPI_CHK(mbedtls_mpi_mod_mpi(&data_r_e, &data_r_e, &pkey->N));
   1208 
   1209     outsize = (mbedtls_mpi_bitlen(&data_r_e) + 7) / 8;
   1210     outbuf = malloc(outsize);
   1211     if (outsize != 0 && !outbuf) {
   1212         ret = -1;
   1213         goto cleanup;
   1214     }
   1215 
   1216     MBEDTLS_MPI_CHK(mbedtls_mpi_write_binary(&data_r_e, outbuf, outsize));
   1217 
   1218     *buf = outbuf;
   1219     *buf_size = outsize;
   1220     ret = 0;
   1221 
   1222 cleanup:
   1223     mbedtls_mpi_free(&data);
   1224     mbedtls_mpi_free(&bkey);
   1225     mbedtls_mpi_free(&r_e);
   1226     mbedtls_mpi_free(&data_r_e);
   1227     return ret;
   1228 }
   1229 
   1230 int
   1231 rsa_unblind (const mbedtls_mpi *sig_blinded,
   1232              const BlindingKeySecret *bks,
   1233              const RsaPub *pkey,
   1234              mbedtls_mpi *sig_ret)
   1235 {
   1236     mbedtls_mpi bkey, r_inv, ubsig;
   1237     int ret;
   1238 
   1239     mbedtls_mpi_init(&bkey);
   1240     mbedtls_mpi_init(&r_inv);
   1241     mbedtls_mpi_init(&ubsig);
   1242 
   1243     MBEDTLS_MPI_CHK(rsa_blinding_key_derive (&bkey, pkey, bks));
   1244     MBEDTLS_MPI_CHK(mbedtls_mpi_inv_mod(&r_inv, &bkey, &pkey->N));
   1245     MBEDTLS_MPI_CHK(mbedtls_mpi_mul_mpi(&ubsig, sig_blinded, &r_inv));
   1246     MBEDTLS_MPI_CHK(mbedtls_mpi_mod_mpi(sig_ret, &ubsig, &pkey->N));
   1247 
   1248 cleanup:
   1249     mbedtls_mpi_free(&bkey);
   1250     mbedtls_mpi_free(&r_inv);
   1251     mbedtls_mpi_free(&ubsig);
   1252     return ret;
   1253 }
   1254 
   1255 
   1256 int
   1257 rsa_verify(const HashCode *hash,
   1258            const mbedtls_mpi *sig,
   1259            const RsaPub *pkey)
   1260 {
   1261     mbedtls_mpi r;
   1262     mbedtls_mpi sig_e;
   1263     int ret;
   1264 
   1265     mbedtls_mpi_init(&r);
   1266     mbedtls_mpi_init(&sig_e);
   1267 
   1268     if (mbedtls_mpi_cmp_int(sig, 0) < 0 ||
   1269         mbedtls_mpi_cmp_mpi(sig, &pkey->N) >= 0) {
   1270         ret = -1;
   1271         goto cleanup;
   1272     }
   1273 
   1274     /* Can fail if RSA key is malicious since rsa_gcd_validate failed here.
   1275      * It should have failed during GNUNET_CRYPTO_rsa_blind too though,
   1276      * so the exchange is being malicious in an unfamilair way, maybe
   1277      * just trying to crash us.  Arguably, we've only an internal error
   1278      * though because we should've detected this in our previous call
   1279      * to GNUNET_CRYPTO_rsa_unblind. *///
   1280     MBEDTLS_MPI_CHK(rsa_full_domain_hash(&r, pkey, hash));
   1281 
   1282     MBEDTLS_MPI_CHK(mbedtls_mpi_exp_mod(&sig_e, sig, &pkey->e, &pkey->N, NULL));
   1283 
   1284     if (0 != mbedtls_mpi_cmp_mpi(&r, &sig_e)) {
   1285         ret = -1;
   1286     } else {
   1287         ret = 0;
   1288     }
   1289 
   1290 cleanup:
   1291     mbedtls_mpi_free(&r);
   1292     mbedtls_mpi_free(&sig_e);
   1293     return ret;
   1294 }
   1295 
   1296 
   1297 /**
   1298  * (hmsg, bks, rsaPub) -> blinded
   1299  */
   1300 static JSValue js_talercrypto_rsa_blind(JSContext *ctx, JSValueConst this_val,
   1301                                         int argc, JSValueConst *argv)
   1302 {
   1303     HashCode *hmsg;
   1304     BlindingKeySecret *bks;
   1305     uint8_t *rsa_enc;
   1306     size_t rsa_enc_len;
   1307     RsaPub rsa_pub;
   1308     JSValue ret_val = JS_UNDEFINED;
   1309     uint8_t *out_buf = NULL;
   1310     size_t out_len;
   1311 
   1312     rsa_public_key_init(&rsa_pub);
   1313 
   1314     hmsg = (HashCode *) expect_fixed_buffer(ctx, argv[0], 64, "hmsg");
   1315     if (!hmsg) {
   1316         ret_val = JS_EXCEPTION;
   1317         goto cleanup;
   1318     }
   1319     bks = (BlindingKeySecret *) expect_fixed_buffer(ctx, argv[1], 32, "bks");
   1320     if (!bks) {
   1321         ret_val = JS_EXCEPTION;
   1322         goto cleanup;
   1323     }
   1324     rsa_enc = JS_GetArrayBuffer(ctx, &rsa_enc_len, argv[2]);
   1325     if (!rsa_enc) {
   1326         ret_val = JS_EXCEPTION;
   1327         goto cleanup;
   1328     }
   1329     if (0 != rsa_public_key_decode(&rsa_pub, rsa_enc, rsa_enc_len)) {
   1330         ret_val = JS_ThrowTypeError(ctx, "rsa pubkey");
   1331         goto cleanup;
   1332     }
   1333     if (0 != rsa_blind(hmsg, bks, &rsa_pub, &out_buf, &out_len)) {
   1334         ret_val = JS_ThrowInternalError(ctx, "blinding failed");
   1335         goto cleanup;
   1336     }
   1337 
   1338     ret_val = make_js_ta_copy(ctx, out_buf, out_len);
   1339 cleanup:
   1340     if (NULL != out_buf) {
   1341         free(out_buf);
   1342         out_buf = NULL;
   1343     }
   1344     rsa_public_key_free(&rsa_pub);
   1345     return ret_val;
   1346 }
   1347 
   1348 /**
   1349  * (blindSig, rsaPub, bks) -> ubsig
   1350  */
   1351 static JSValue js_talercrypto_rsa_unblind(JSContext *ctx, JSValueConst this_val,
   1352                                         int argc, JSValueConst *argv)
   1353 {
   1354     JSValue ret_val = JS_UNDEFINED;
   1355     mbedtls_mpi bsig;
   1356     mbedtls_mpi sig_ret;
   1357     RsaPub rsa_pub;
   1358     BlindingKeySecret *bks;
   1359 
   1360     mbedtls_mpi_init(&bsig);
   1361     mbedtls_mpi_init(&sig_ret);
   1362     rsa_public_key_init(&rsa_pub);
   1363 
   1364     if (0 != expect_mpi(ctx, argv[0], "blindSig", &bsig)) {
   1365         ret_val = JS_EXCEPTION;
   1366         goto cleanup;
   1367     }
   1368     if (0 != expect_rsa_pub(ctx, argv[1], "rsaPub", &rsa_pub)) {
   1369         ret_val = JS_EXCEPTION;
   1370         goto cleanup;
   1371     }
   1372     bks = (BlindingKeySecret *) expect_fixed_buffer(ctx, argv[2], 32, "bks");
   1373     if (!bks) {
   1374         ret_val = JS_EXCEPTION;
   1375         goto cleanup;
   1376     }
   1377 
   1378     if (0 != rsa_unblind(&bsig, bks, &rsa_pub, &sig_ret)) {
   1379         ret_val = JS_ThrowInternalError(ctx, "unblinding failed");
   1380         goto cleanup;
   1381     }
   1382 
   1383     ret_val = make_js_ta_mpi(ctx, &sig_ret);
   1384 
   1385 cleanup:
   1386     mbedtls_mpi_free(&bsig);
   1387     mbedtls_mpi_free(&sig_ret);
   1388     rsa_public_key_free(&rsa_pub);
   1389     return ret_val;
   1390 }
   1391 
   1392 /**
   1393  * (hm, rsaSig, rsaPub) -> bool
   1394  */
   1395 static JSValue js_talercrypto_rsa_verify(JSContext *ctx, JSValueConst this_val,
   1396                                         int argc, JSValueConst *argv)
   1397 {
   1398     JSValue ret_val = JS_UNDEFINED;
   1399     HashCode *hmsg;
   1400     mbedtls_mpi sig;
   1401     RsaPub rsa_pub;
   1402 
   1403     mbedtls_mpi_init(&sig);
   1404     rsa_public_key_init(&rsa_pub);
   1405 
   1406     hmsg = (HashCode *) expect_fixed_buffer(ctx, argv[0], 64, "hmsg");
   1407     if (!hmsg) {
   1408         ret_val = JS_EXCEPTION;
   1409         goto cleanup;
   1410     }
   1411 
   1412     if (0 != expect_mpi(ctx, argv[1], "sig", &sig)) {
   1413         ret_val = JS_EXCEPTION;
   1414         goto cleanup;
   1415     }
   1416 
   1417     if (0 != expect_rsa_pub(ctx, argv[2], "rsaPub", &rsa_pub)) {
   1418         ret_val = JS_EXCEPTION;
   1419         goto cleanup;
   1420     }
   1421 
   1422     if (0 != rsa_verify(hmsg, &sig, &rsa_pub)) {
   1423         ret_val = JS_FALSE;
   1424         goto cleanup;
   1425     }
   1426 
   1427     ret_val = JS_TRUE;
   1428 
   1429 cleanup:
   1430     mbedtls_mpi_free(&sig);
   1431     rsa_public_key_free(&rsa_pub);
   1432     return ret_val;
   1433 
   1434 }
   1435 
   1436 // (ArrayBuffer | TypedArray) => string
   1437 static JSValue js_decode_utf8(JSContext *ctx, JSValueConst this_val,
   1438                               int argc, JSValueConst *argv)
   1439 {
   1440     size_t psize;
   1441     uint8_t *utf8_buf;
   1442     JSValue ret_val;
   1443 
   1444     utf8_buf = JS_GetArrayBuffer(ctx, &psize, argv[0]);
   1445     if (NULL == utf8_buf) {
   1446         goto exception;
   1447     }
   1448     return JS_NewStringLen(ctx, (char *) utf8_buf, psize);
   1449 done:
   1450     return ret_val;
   1451 exception:
   1452     ret_val = JS_EXCEPTION;
   1453     goto done;
   1454 }
   1455 
   1456 static JSValue js_structured_clone(JSContext *ctx, JSValueConst this_val,
   1457                                    int argc, JSValueConst *argv)
   1458 {
   1459     uint8_t *buf;
   1460     size_t len;
   1461     JSValue obj;
   1462 
   1463     buf = JS_WriteObject(ctx, &len, argv[0], JS_WRITE_OBJ_REFERENCE);
   1464 
   1465     if (NULL == buf) {
   1466         return JS_EXCEPTION;
   1467     }
   1468 
   1469     obj = JS_ReadObject(ctx, buf, len, JS_WRITE_OBJ_REFERENCE);
   1470     js_free(ctx, buf);
   1471     return obj;
   1472 }
   1473 
   1474 static JSClassID js_hash_state_class_id;
   1475 
   1476 typedef struct {
   1477     crypto_hash_sha512_state h;
   1478     int finalized;
   1479 } TART_HashState;
   1480 
   1481 
   1482 static void js_hash_state_finalizer(JSRuntime *rt, JSValue val)
   1483 {
   1484     TART_HashState *s = JS_GetOpaque(val, js_hash_state_class_id);
   1485     /* Note: 's' can be NULL in case JS_SetOpaque() was not called */
   1486     js_free_rt(rt, s);
   1487 }
   1488 
   1489 static JSClassDef js_hash_state_class = {
   1490     "HashState",
   1491     .finalizer = js_hash_state_finalizer,
   1492 };
   1493 
   1494 static JSValue js_talercrypto_hash_state_init(JSContext *ctx, JSValue this_val,
   1495                                               int argc, JSValueConst *argv)
   1496 {
   1497     TART_HashState *hstate;
   1498     JSValue obj;
   1499 
   1500     hstate = js_malloc_rt(JS_GetRuntime(ctx), sizeof (TART_HashState));
   1501     if (!hstate) {
   1502         obj = JS_EXCEPTION;
   1503         goto done;
   1504     }
   1505     hstate->finalized = FALSE;
   1506     obj = JS_NewObjectClass(ctx, js_hash_state_class_id);
   1507     if (JS_IsException(obj)) {
   1508         goto done;
   1509     }
   1510     crypto_hash_sha512_init(&hstate->h);
   1511     JS_SetOpaque(obj, hstate);
   1512     hstate = NULL;
   1513     return obj;
   1514 done:
   1515     if (NULL != hstate) {
   1516         js_free_rt(JS_GetRuntime(ctx), hstate);
   1517     }
   1518     return obj;
   1519 }
   1520 
   1521 static JSValue js_talercrypto_hash_state_update(JSContext *ctx, JSValue this_val,
   1522                                               int argc, JSValueConst *argv)
   1523 {
   1524     JSValue state = argv[0];
   1525     JSValue data_val = argv[1];
   1526     TART_HashState *hstate;
   1527     uint8_t *data;
   1528     size_t data_len;
   1529 
   1530     hstate = JS_GetOpaque(state, js_hash_state_class_id);
   1531 
   1532     if (!hstate) {
   1533         return JS_ThrowTypeError(ctx, "expected HashState");
   1534     }
   1535 
   1536     if (hstate->finalized) {
   1537         return JS_ThrowTypeError(ctx, "already finalized");
   1538     }
   1539 
   1540     data = JS_GetArrayBuffer(ctx, &data_len, data_val);
   1541 
   1542     if (!data) {
   1543         return JS_EXCEPTION;
   1544     }
   1545 
   1546     if (0 != crypto_hash_sha512_update(&hstate->h, data, data_len)) {
   1547         return JS_ThrowInternalError(ctx, "hashing failed");
   1548     }
   1549 
   1550     return JS_UNDEFINED;
   1551 }
   1552 
   1553 static JSValue js_talercrypto_hash_state_finish(JSContext *ctx, JSValue this_val,
   1554                                               int argc, JSValueConst *argv)
   1555 {
   1556     JSValue state = argv[0];
   1557     TART_HashState *hstate;
   1558     uint8_t hashval[crypto_hash_sha512_BYTES];
   1559 
   1560     hstate = JS_GetOpaque(state, js_hash_state_class_id);
   1561 
   1562     if (!hstate) {
   1563         return JS_ThrowTypeError(ctx, "expected HashState");
   1564     }
   1565 
   1566     if (hstate->finalized) {
   1567         return JS_ThrowTypeError(ctx, "already finalized");
   1568     }
   1569 
   1570     if (0 != crypto_hash_sha512_final(&hstate->h, hashval)) {
   1571         return JS_ThrowInternalError(ctx, "hashing failed");
   1572     }
   1573 
   1574     hstate->finalized = TRUE;
   1575 
   1576     return make_js_ta_copy(ctx, hashval, crypto_hash_sha512_BYTES);
   1577 }
   1578 
   1579 static JSClassID js_sqlite3_database_class_id;
   1580 static JSClassID js_sqlite3_statement_class_id;
   1581 static JSClassID js_sqlite3_error_class_id;
   1582 
   1583 static void js_sqlite3_database_finalizer(JSRuntime *rt, JSValue val)
   1584 {
   1585     sqlite3 *sqlite3_db;
   1586     sqlite3_db = JS_GetOpaque(val, js_sqlite3_database_class_id);
   1587     if (sqlite3_db) {
   1588         (void)sqlite3_close_v2(sqlite3_db);
   1589     }
   1590     JS_SetOpaque(val, NULL);
   1591 }
   1592 
   1593 static void js_sqlite3_statement_finalizer(JSRuntime *rt, JSValue val)
   1594 {
   1595     sqlite3_stmt *stmt;
   1596 
   1597     stmt = JS_GetOpaque(val, js_sqlite3_statement_class_id);
   1598     if (stmt) {
   1599         // The return code reports the last evaluation error, not whether the
   1600         // statement resource was released, so there is nothing to retry here.
   1601         (void)sqlite3_finalize(stmt);
   1602     }
   1603     JS_SetOpaque(val, NULL);
   1604 }
   1605 
   1606 static JSClassDef js_sqlite3_database_class = {
   1607     .class_name = "Sqlite3Database",
   1608     .finalizer = js_sqlite3_database_finalizer,
   1609 };
   1610 
   1611 static JSClassDef js_sqlite3_statement_class = {
   1612     .class_name = "Sqlite3Statement",
   1613     .finalizer = js_sqlite3_statement_finalizer,
   1614 };
   1615 
   1616 /*
   1617  * Sqlite3Error instances use QuickJS' built-in Error class so that they get
   1618  * normal Error behaviour and stack traces.  This otherwise-unused class ID
   1619  * gives each context a place to retain the Sqlite3Error prototype.
   1620  */
   1621 static JSClassDef js_sqlite3_error_class = {
   1622     .class_name = "Sqlite3Error",
   1623 };
   1624 
   1625 #define ERRCASE(c) case c: return #c
   1626 
   1627 const char *translate_sqlite3_err_to_string(int errcode)
   1628 {
   1629     switch (errcode) {
   1630         ERRCASE(SQLITE_OK);
   1631         ERRCASE(SQLITE_ERROR);
   1632         ERRCASE(SQLITE_INTERNAL);
   1633         ERRCASE(SQLITE_PERM);
   1634         ERRCASE(SQLITE_ABORT);
   1635         ERRCASE(SQLITE_BUSY);
   1636         ERRCASE(SQLITE_LOCKED);
   1637         ERRCASE(SQLITE_NOMEM);
   1638         ERRCASE(SQLITE_READONLY);
   1639         ERRCASE(SQLITE_INTERRUPT);
   1640         ERRCASE(SQLITE_IOERR);
   1641         ERRCASE(SQLITE_CORRUPT);
   1642         ERRCASE(SQLITE_NOTFOUND);
   1643         ERRCASE(SQLITE_FULL);
   1644         ERRCASE(SQLITE_CANTOPEN);
   1645         ERRCASE(SQLITE_PROTOCOL);
   1646         ERRCASE(SQLITE_EMPTY);
   1647         ERRCASE(SQLITE_SCHEMA);
   1648         ERRCASE(SQLITE_TOOBIG);
   1649         ERRCASE(SQLITE_CONSTRAINT);
   1650         ERRCASE(SQLITE_MISMATCH);
   1651         ERRCASE(SQLITE_MISUSE);
   1652         ERRCASE(SQLITE_NOLFS);
   1653         ERRCASE(SQLITE_AUTH);
   1654         ERRCASE(SQLITE_FORMAT);
   1655         ERRCASE(SQLITE_RANGE);
   1656         ERRCASE(SQLITE_NOTADB);
   1657         ERRCASE(SQLITE_NOTICE);
   1658         ERRCASE(SQLITE_WARNING);
   1659         ERRCASE(SQLITE_ROW);
   1660         ERRCASE(SQLITE_DONE);
   1661         ERRCASE(SQLITE_ERROR_MISSING_COLLSEQ);
   1662         ERRCASE(SQLITE_ERROR_RETRY);
   1663         ERRCASE(SQLITE_ERROR_SNAPSHOT);
   1664         ERRCASE(SQLITE_IOERR_READ);
   1665         ERRCASE(SQLITE_IOERR_SHORT_READ);
   1666         ERRCASE(SQLITE_IOERR_WRITE);
   1667         ERRCASE(SQLITE_IOERR_FSYNC);
   1668         ERRCASE(SQLITE_IOERR_DIR_FSYNC);
   1669         ERRCASE(SQLITE_IOERR_TRUNCATE);
   1670         ERRCASE(SQLITE_IOERR_FSTAT);
   1671         ERRCASE(SQLITE_IOERR_UNLOCK);
   1672         ERRCASE(SQLITE_IOERR_RDLOCK);
   1673         ERRCASE(SQLITE_IOERR_DELETE);
   1674         ERRCASE(SQLITE_IOERR_BLOCKED);
   1675         ERRCASE(SQLITE_IOERR_NOMEM);
   1676         ERRCASE(SQLITE_IOERR_ACCESS);
   1677         ERRCASE(SQLITE_IOERR_CHECKRESERVEDLOCK);
   1678         ERRCASE(SQLITE_IOERR_LOCK);
   1679         ERRCASE(SQLITE_IOERR_CLOSE);
   1680         ERRCASE(SQLITE_IOERR_DIR_CLOSE);
   1681         ERRCASE(SQLITE_IOERR_SHMOPEN);
   1682         ERRCASE(SQLITE_IOERR_SHMSIZE);
   1683         ERRCASE(SQLITE_IOERR_SHMLOCK);
   1684         ERRCASE(SQLITE_IOERR_SHMMAP);
   1685         ERRCASE(SQLITE_IOERR_SEEK);
   1686         ERRCASE(SQLITE_IOERR_DELETE_NOENT);
   1687         ERRCASE(SQLITE_IOERR_MMAP);
   1688         ERRCASE(SQLITE_IOERR_GETTEMPPATH);
   1689         ERRCASE(SQLITE_IOERR_CONVPATH);
   1690         ERRCASE(SQLITE_IOERR_VNODE);
   1691         ERRCASE(SQLITE_IOERR_AUTH);
   1692         ERRCASE(SQLITE_IOERR_BEGIN_ATOMIC);
   1693         ERRCASE(SQLITE_IOERR_COMMIT_ATOMIC);
   1694         ERRCASE(SQLITE_IOERR_ROLLBACK_ATOMIC);
   1695         ERRCASE(SQLITE_IOERR_DATA);
   1696         ERRCASE(SQLITE_IOERR_CORRUPTFS);
   1697 #ifdef SQLITE_IOERR_IN_PAGE
   1698         ERRCASE(SQLITE_IOERR_IN_PAGE);
   1699 #endif
   1700         ERRCASE(SQLITE_LOCKED_SHAREDCACHE);
   1701         ERRCASE(SQLITE_LOCKED_VTAB);
   1702         ERRCASE(SQLITE_BUSY_RECOVERY);
   1703         ERRCASE(SQLITE_BUSY_SNAPSHOT);
   1704         ERRCASE(SQLITE_BUSY_TIMEOUT);
   1705         ERRCASE(SQLITE_CANTOPEN_NOTEMPDIR);
   1706         ERRCASE(SQLITE_CANTOPEN_ISDIR);
   1707         ERRCASE(SQLITE_CANTOPEN_FULLPATH);
   1708         ERRCASE(SQLITE_CANTOPEN_CONVPATH);
   1709         ERRCASE(SQLITE_CANTOPEN_DIRTYWAL);
   1710         ERRCASE(SQLITE_CANTOPEN_SYMLINK);
   1711         ERRCASE(SQLITE_CORRUPT_VTAB);
   1712         ERRCASE(SQLITE_CORRUPT_SEQUENCE);
   1713         ERRCASE(SQLITE_CORRUPT_INDEX);
   1714         ERRCASE(SQLITE_READONLY_RECOVERY);
   1715         ERRCASE(SQLITE_READONLY_CANTLOCK);
   1716         ERRCASE(SQLITE_READONLY_ROLLBACK);
   1717         ERRCASE(SQLITE_READONLY_DBMOVED);
   1718         ERRCASE(SQLITE_READONLY_CANTINIT);
   1719         ERRCASE(SQLITE_READONLY_DIRECTORY);
   1720         ERRCASE(SQLITE_ABORT_ROLLBACK);
   1721         ERRCASE(SQLITE_CONSTRAINT_CHECK);
   1722         ERRCASE(SQLITE_CONSTRAINT_COMMITHOOK);
   1723         ERRCASE(SQLITE_CONSTRAINT_FOREIGNKEY);
   1724         ERRCASE(SQLITE_CONSTRAINT_FUNCTION);
   1725         ERRCASE(SQLITE_CONSTRAINT_NOTNULL);
   1726         ERRCASE(SQLITE_CONSTRAINT_PRIMARYKEY);
   1727         ERRCASE(SQLITE_CONSTRAINT_TRIGGER);
   1728         ERRCASE(SQLITE_CONSTRAINT_UNIQUE);
   1729         ERRCASE(SQLITE_CONSTRAINT_VTAB);
   1730         ERRCASE(SQLITE_CONSTRAINT_ROWID);
   1731         ERRCASE(SQLITE_CONSTRAINT_PINNED);
   1732         ERRCASE(SQLITE_CONSTRAINT_DATATYPE);
   1733         ERRCASE(SQLITE_NOTICE_RECOVER_WAL);
   1734         ERRCASE(SQLITE_NOTICE_RECOVER_ROLLBACK);
   1735 #ifdef SQLITE_NOTICE_RBU
   1736         ERRCASE(SQLITE_NOTICE_RBU);
   1737 #endif
   1738         ERRCASE(SQLITE_WARNING_AUTOINDEX);
   1739         ERRCASE(SQLITE_AUTH_USER);
   1740         ERRCASE(SQLITE_OK_LOAD_PERMANENTLY);
   1741         ERRCASE(SQLITE_OK_SYMLINK);
   1742         default:
   1743             return "SQLITE_UNKNOWN_ERRCODE";
   1744     }
   1745 }
   1746 
   1747 
   1748 static JSValue new_sqlite3_error_with_proto(JSContext *ctx,
   1749                                              JSValueConst proto)
   1750 {
   1751     JSValue obj;
   1752 
   1753     obj = JS_NewError(ctx);
   1754     if (JS_IsException(obj)) {
   1755         return obj;
   1756     }
   1757     if (JS_SetPrototype(ctx, obj, proto) < 0) {
   1758         JS_FreeValue(ctx, obj);
   1759         return JS_EXCEPTION;
   1760     }
   1761     return obj;
   1762 }
   1763 
   1764 static JSValue new_sqlite3_error(JSContext *ctx)
   1765 {
   1766     JSValue obj;
   1767     JSValue proto;
   1768 
   1769     proto = JS_GetClassProto(ctx, js_sqlite3_error_class_id);
   1770     if (JS_IsException(proto)) {
   1771         return proto;
   1772     }
   1773     obj = new_sqlite3_error_with_proto(ctx, proto);
   1774     JS_FreeValue(ctx, proto);
   1775     return obj;
   1776 }
   1777 
   1778 static JSValue js_sqlite3_error_constructor(JSContext *ctx,
   1779                                              JSValueConst new_target,
   1780                                              int argc,
   1781                                              JSValueConst *argv)
   1782 {
   1783     JSValue obj;
   1784     JSValue proto;
   1785 
   1786     proto = JS_GetPropertyStr(ctx, new_target, "prototype");
   1787     if (JS_IsException(proto)) {
   1788         return proto;
   1789     }
   1790     obj = new_sqlite3_error_with_proto(ctx, proto);
   1791     JS_FreeValue(ctx, proto);
   1792     if (JS_IsException(obj)) {
   1793         return obj;
   1794     }
   1795     if (argc > 0 && !JS_IsUndefined(argv[0])) {
   1796         JSValue message = JS_ToString(ctx, argv[0]);
   1797         if (JS_IsException(message) ||
   1798             JS_DefinePropertyValueStr(
   1799                 ctx,
   1800                 obj,
   1801                 "message",
   1802                 message,
   1803                 JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE) < 0) {
   1804             JS_FreeValue(ctx, obj);
   1805             return JS_EXCEPTION;
   1806         }
   1807     }
   1808     return obj;
   1809 }
   1810 
   1811 static JSValue throw_sqlite3_error(JSContext *ctx, sqlite3 *db)
   1812 {
   1813     JSValue obj;
   1814     int error_code;
   1815 
   1816     error_code = sqlite3_extended_errcode(db);
   1817     obj = new_sqlite3_error(ctx);
   1818     if (JS_IsException(obj)) {
   1819         return obj;
   1820     }
   1821 
   1822     if (JS_DefinePropertyValueStr(
   1823         ctx,
   1824         obj,
   1825         "message",
   1826         JS_NewString(ctx, sqlite3_errmsg(db)),
   1827         JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE) < 0 ||
   1828         JS_DefinePropertyValueStr(
   1829         ctx,
   1830         obj,
   1831         "code",
   1832         JS_NewString(ctx, translate_sqlite3_err_to_string(error_code)),
   1833         JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE) < 0 ||
   1834         JS_DefinePropertyValueStr(
   1835         ctx,
   1836         obj,
   1837         "errno",
   1838         JS_NewInt32(ctx, error_code),
   1839         JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE) < 0) {
   1840         JS_FreeValue(ctx, obj);
   1841         return JS_EXCEPTION;
   1842     }
   1843     return JS_Throw(ctx, obj);
   1844 }
   1845 
   1846 #define MAX_SAFE_INTEGER (((int64_t)1 << 53) - 1)
   1847 #define MIN_SAFE_INTEGER (-(((int64_t)1 << 53) - 1))
   1848 
   1849 static int sqlite3_open_boolean_option(JSContext *ctx,
   1850                                        JSValueConst options,
   1851                                        const char *name,
   1852                                        int *result)
   1853 {
   1854     JSValue value;
   1855 
   1856     value = JS_GetPropertyStr(ctx, options, name);
   1857     if (JS_IsException(value)) {
   1858         return -1;
   1859     }
   1860     if (JS_IsUndefined(value)) {
   1861         *result = 0;
   1862     } else if (!JS_IsBool(value)) {
   1863         JS_FreeValue(ctx, value);
   1864         JS_ThrowTypeError(ctx, "sqlite3Open option '%s' must be a boolean", name);
   1865         return -1;
   1866     } else {
   1867         *result = JS_ToBool(ctx, value);
   1868     }
   1869     JS_FreeValue(ctx, value);
   1870     return 0;
   1871 }
   1872 
   1873 static int sqlite_uri_path_char(unsigned char c)
   1874 {
   1875     return (c >= 'a' && c <= 'z') ||
   1876            (c >= 'A' && c <= 'Z') ||
   1877            (c >= '0' && c <= '9') ||
   1878            c == '/' || c == '-' || c == '.' || c == '_' || c == '~';
   1879 }
   1880 
   1881 static char *sqlite3_immutable_uri(const char *filename)
   1882 {
   1883     static const char hex[] = "0123456789ABCDEF";
   1884     static const char prefix[] = "file:";
   1885     static const char suffix[] = "?immutable=1";
   1886     size_t filename_len;
   1887     size_t allocation_size;
   1888     char *uri;
   1889     char *p;
   1890 
   1891     filename_len = strlen(filename);
   1892     if (filename_len > (SIZE_MAX - sizeof(prefix) - sizeof(suffix)) / 3) {
   1893         return NULL;
   1894     }
   1895     allocation_size = sizeof(prefix) - 1 + filename_len * 3 + sizeof(suffix);
   1896     uri = sqlite3_malloc64(allocation_size);
   1897     if (!uri) {
   1898         return NULL;
   1899     }
   1900     p = uri;
   1901     memcpy(p, prefix, sizeof(prefix) - 1);
   1902     p += sizeof(prefix) - 1;
   1903     for (size_t i = 0; i < filename_len; i++) {
   1904         unsigned char c = (unsigned char)filename[i];
   1905         if (sqlite_uri_path_char(c)) {
   1906             *p++ = (char)c;
   1907         } else {
   1908             *p++ = '%';
   1909             *p++ = hex[c >> 4];
   1910             *p++ = hex[c & 0x0f];
   1911         }
   1912     }
   1913     memcpy(p, suffix, sizeof(suffix));
   1914     return uri;
   1915 }
   1916 
   1917 // (path: string, options?: { readonly?: boolean, immutable?: boolean }) => Sqlite3Database
   1918 static JSValue js_sqlite3_open(JSContext *ctx, JSValue this_val,
   1919                                int argc, JSValueConst *argv)
   1920 {
   1921     JSValue ret_val = JS_UNINITIALIZED;
   1922     JSValue db_obj = JS_UNINITIALIZED;
   1923     const char *filename = NULL;
   1924     const char *open_filename;
   1925     char *immutable_uri = NULL;
   1926     sqlite3 *sqlite3_db = NULL;
   1927     int readonly = 0;
   1928     int immutable = 0;
   1929     int open_flags;
   1930     int ret;
   1931 
   1932     if (argc < 1 || !JS_IsString(argv[0])) {
   1933         ret_val = JS_ThrowTypeError(ctx, "filename argument required");
   1934         goto done;
   1935     }
   1936 
   1937     if (argc > 1 && !JS_IsUndefined(argv[1])) {
   1938         if (!JS_IsObject(argv[1])) {
   1939             ret_val = JS_ThrowTypeError(ctx, "sqlite3Open options must be an object");
   1940             goto done;
   1941         }
   1942         if (sqlite3_open_boolean_option(ctx, argv[1], "readonly", &readonly) < 0 ||
   1943             sqlite3_open_boolean_option(ctx, argv[1], "immutable", &immutable) < 0) {
   1944             ret_val = JS_EXCEPTION;
   1945             goto done;
   1946         }
   1947     }
   1948     if (immutable) {
   1949         readonly = 1;
   1950     }
   1951 
   1952     filename = JS_ToCString(ctx, argv[0]);
   1953 
   1954     if (!filename) {
   1955         ret_val = JS_ThrowTypeError(ctx, "filename argument required");
   1956         goto done;
   1957     }
   1958 
   1959     open_filename = filename;
   1960     open_flags = readonly
   1961         ? SQLITE_OPEN_READONLY
   1962         : SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE;
   1963     if (immutable) {
   1964         immutable_uri = sqlite3_immutable_uri(filename);
   1965         if (!immutable_uri) {
   1966             ret_val = JS_ThrowOutOfMemory(ctx);
   1967             goto done;
   1968         }
   1969         open_filename = immutable_uri;
   1970         open_flags |= SQLITE_OPEN_URI;
   1971     }
   1972 
   1973 //    fprintf(stderr, "opening sqlite3 db at %s\n", filename),
   1974     ret = sqlite3_open_v2(open_filename, &sqlite3_db, open_flags, NULL);
   1975     if (SQLITE_OK != ret) {
   1976         if (NULL == sqlite3_db) {
   1977           // sqlite3 was unable to even allocate memory
   1978           ret_val = JS_ThrowInternalError(ctx, "unable to open database (OOM)");
   1979         } else {
   1980           // get error details from DB before we close it
   1981           fprintf(stderr, "sqlite3_open failed: %s / %s\n",
   1982                   sqlite3_errstr(ret),
   1983                   sqlite3_errmsg(sqlite3_db));
   1984           ret_val = throw_sqlite3_error(ctx, sqlite3_db);
   1985           fprintf(stderr, "calling sqlite3 close on failed db\n");
   1986           (void)sqlite3_close_v2(sqlite3_db);
   1987         }
   1988         goto done;
   1989     }
   1990     db_obj = JS_NewObjectClass(ctx, js_sqlite3_database_class_id);
   1991     if (JS_IsException(db_obj)) {
   1992         (void) sqlite3_close_v2(sqlite3_db);
   1993         ret_val = JS_EXCEPTION;
   1994         goto done;
   1995     }
   1996     JS_SetOpaque(db_obj, sqlite3_db);
   1997     ret_val = db_obj;
   1998 done:
   1999     sqlite3_free(immutable_uri);
   2000     JS_FreeCString(ctx, filename);
   2001     return ret_val;
   2002 }
   2003 
   2004 // (handle: Sqlite3Database) -> undefined
   2005 static JSValue js_sqlite3_close(JSContext *ctx, JSValue this_val,
   2006                                               int argc, JSValueConst *argv)
   2007 {
   2008     JSValue db_handle;
   2009     sqlite3 *sqlite3_db;
   2010     int ret;
   2011 
   2012     if (argc < 1 ||
   2013         JS_GetClassID(argv[0]) != js_sqlite3_database_class_id) {
   2014         return JS_ThrowTypeError(ctx, "expected sqlite3 database handle");
   2015     }
   2016     db_handle = argv[0];
   2017 
   2018     sqlite3_db = JS_GetOpaque(db_handle, js_sqlite3_database_class_id);
   2019 
   2020     if (!sqlite3_db) {
   2021         return JS_ThrowTypeError(ctx, "invalid sqlite3 database handle");
   2022     }
   2023 
   2024     /*
   2025      * Unlike close_v2(), sqlite3_close() refuses to turn a connection with
   2026      * live statements into a zombie.  Keep the JS handle valid on SQLITE_BUSY
   2027      * so the caller can finalize the statements and retry safely.
   2028      */
   2029     ret = sqlite3_close(sqlite3_db);
   2030     if (SQLITE_OK != ret) {
   2031         return throw_sqlite3_error(ctx, sqlite3_db);
   2032     }
   2033     JS_SetOpaque(db_handle, NULL);
   2034     return JS_UNDEFINED;
   2035 }
   2036 
   2037 // (handle: Sqlite3Database, stmt: string) => Sqlite3Statement
   2038 static JSValue js_sqlite3_prepare(JSContext *ctx, JSValue this_val,
   2039                                               int argc, JSValueConst *argv)
   2040 {
   2041     JSValue db_handle;
   2042     JSValue stmt_str;
   2043     JSValue ret_val = JS_UNDEFINED;
   2044     JSValue stmt_obj = JS_UNDEFINED;
   2045     int ret;
   2046     sqlite3 *sqlite3_db;
   2047     sqlite3_stmt *stmt;
   2048     const char *stmt_cstr;
   2049     const char *tail;
   2050 
   2051     if (argc < 2 ||
   2052         JS_GetClassID(argv[0]) != js_sqlite3_database_class_id) {
   2053         return JS_ThrowTypeError(ctx, "expected database handle and SQL string");
   2054     }
   2055     db_handle = argv[0];
   2056     stmt_str = argv[1];
   2057 
   2058     sqlite3_db = JS_GetOpaque(db_handle, js_sqlite3_database_class_id);
   2059 
   2060     if (!sqlite3_db) {
   2061         return JS_ThrowTypeError(ctx, "invalid sqlite3 database handle");
   2062     }
   2063 
   2064     stmt_cstr = JS_ToCString(ctx, stmt_str);
   2065 
   2066     if (!stmt_cstr) {
   2067         ret_val = JS_ThrowTypeError(ctx, "invalid prepared statement, string expected");
   2068         goto done;
   2069     }
   2070 
   2071     ret = sqlite3_prepare_v3(sqlite3_db, stmt_cstr, (int) strlen(stmt_cstr), 0, &stmt, &tail);
   2072     if (SQLITE_OK != ret) {
   2073         ret_val = throw_sqlite3_error(ctx, sqlite3_db);
   2074         goto done;
   2075     }
   2076  
   2077     stmt_obj = JS_NewObjectClass(ctx, js_sqlite3_statement_class_id);
   2078     if (JS_IsException(stmt_obj)) {
   2079         sqlite3_finalize(stmt);
   2080         ret_val = JS_EXCEPTION;
   2081         goto done;
   2082     }
   2083     JS_SetOpaque(stmt_obj, stmt);
   2084     /*
   2085      * A statement must keep its database JS object alive.  Otherwise QuickJS
   2086      * could run the database finalizer while the sqlite3_stmt still refers to
   2087      * that connection.
   2088      */
   2089     if (JS_DefinePropertyValueStr(
   2090         ctx,
   2091         stmt_obj,
   2092         "__sqlite3_database_owner",
   2093         JS_DupValue(ctx, db_handle),
   2094         0) < 0) {
   2095         JS_FreeValue(ctx, stmt_obj);
   2096         ret_val = JS_EXCEPTION;
   2097         goto done;
   2098     }
   2099     ret_val = stmt_obj;
   2100 done:
   2101     JS_FreeCString(ctx, stmt_cstr);
   2102     return ret_val;
   2103 }
   2104 
   2105 
   2106 static JSValue js_sqlite3_finalize(JSContext *ctx, JSValue this_val,
   2107                                               int argc, JSValueConst *argv)
   2108 {
   2109     sqlite3_stmt *stmt;
   2110 
   2111     if (argc < 1 ||
   2112         JS_GetClassID(argv[0]) != js_sqlite3_statement_class_id) {
   2113         return JS_ThrowTypeError(ctx, "expected sqlite3 statement handle");
   2114     }
   2115     stmt = JS_GetOpaque(argv[0], js_sqlite3_statement_class_id);
   2116     if (!stmt) {
   2117         return JS_UNDEFINED;
   2118     }
   2119     (void)sqlite3_finalize(stmt);
   2120     JS_SetOpaque(argv[0], NULL);
   2121     return JS_UNDEFINED;
   2122 }
   2123 
   2124 static int sql_exec_cb(void *cls, int numcol, char **res, char **colnames) {
   2125     return 0;
   2126 }
   2127 
   2128 static JSValue js_sqlite3_exec(JSContext *ctx, JSValue this_val,
   2129                                               int argc, JSValueConst *argv)
   2130 {
   2131     sqlite3 *sqlite3_db;
   2132     JSValue db_handle = argv[0];
   2133     JSValue stmt_str = argv[1];
   2134     const char *stmt_cstr = NULL;
   2135     int res;
   2136     char *errmsg = NULL;
   2137     JSValue ret_val = JS_UNDEFINED;
   2138 
   2139     sqlite3_db = JS_GetOpaque(db_handle, js_sqlite3_database_class_id);
   2140     if (!sqlite3_db) {
   2141         JS_ThrowTypeError(ctx, "invalid sqlite3 database handle");
   2142         goto exception;
   2143     }
   2144     stmt_cstr = JS_ToCString(ctx, stmt_str);
   2145     if (!stmt_cstr) {
   2146         goto exception;
   2147     }
   2148     res = sqlite3_exec(sqlite3_db, stmt_cstr, &sql_exec_cb, NULL, &errmsg);
   2149     if (SQLITE_OK != res) {
   2150         throw_sqlite3_error(ctx, sqlite3_db);
   2151         goto exception;
   2152     }
   2153 done:
   2154     sqlite3_free(errmsg);
   2155     JS_FreeCString(ctx, stmt_cstr);
   2156     return ret_val;
   2157 exception:
   2158     ret_val = JS_EXCEPTION;
   2159     goto done;
   2160 }
   2161 
   2162 static int find_param_index(JSContext *ctx, sqlite3_stmt *stmt, const char *name)
   2163 {
   2164     int param_index;
   2165     char *prefixed_name = malloc(strlen(name) + 2);
   2166     if (!prefixed_name) {
   2167         JS_ThrowOutOfMemory(ctx);
   2168         return -1;
   2169     }
   2170     memcpy(prefixed_name + 1, name, strlen(name) + 1);
   2171 
   2172     prefixed_name[0] = '$';
   2173     param_index = sqlite3_bind_parameter_index(stmt, prefixed_name);
   2174     if (param_index) {
   2175         goto done;
   2176     }
   2177     prefixed_name[0] = ':';
   2178     param_index = sqlite3_bind_parameter_index(stmt, prefixed_name);
   2179     if (param_index) {
   2180         goto done;
   2181     }
   2182     prefixed_name[0] = '@';
   2183     param_index = sqlite3_bind_parameter_index(stmt, prefixed_name);
   2184     if (param_index) {
   2185         goto done;
   2186     }
   2187 done:
   2188     free(prefixed_name);
   2189     return param_index;
   2190 }
   2191 
   2192 static int bind_from_object(JSContext *ctx, sqlite3_stmt *stmt, JSValueConst obj)
   2193 {
   2194     JSValue val = JS_UNDEFINED;
   2195     int i;
   2196     uint32_t len = 0; /* len of property table */
   2197     JSPropertyEnum *tab;
   2198     const char *key = NULL;
   2199     int retval = 0;
   2200 
   2201     if (JS_IsUndefined(obj)) {
   2202         return 0;
   2203     }
   2204 
   2205     if (JS_GetOwnPropertyNames(ctx, &tab, &len, obj,
   2206                                JS_GPN_STRING_MASK | JS_GPN_ENUM_ONLY) < 0) {
   2207         JS_ThrowTypeError(ctx, "can't get property names");
   2208         return -1;
   2209     }
   2210 
   2211     for (i = 0; i < len; i++) {
   2212         int param_index;
   2213         val = JS_GetProperty(ctx, obj, tab[i].atom);
   2214         if (JS_IsException(val))
   2215             goto fail;
   2216         key = JS_AtomToCString(ctx, tab[i].atom);
   2217         if (!key) {
   2218             goto fail;
   2219         }
   2220         param_index = find_param_index(ctx, stmt, key);
   2221         if (param_index < 0) {
   2222             goto fail;
   2223         }
   2224         if (0 == param_index) {
   2225             // JS_ThrowTypeError(ctx, "unable to bind, named param '%s' not found", key);
   2226             //goto fail;
   2227             // We ignore parameters that are bound but not used.
   2228             goto next;
   2229         }
   2230         if (JS_IsNull(val)) {
   2231             if (SQLITE_OK != sqlite3_bind_null(stmt, param_index)) {
   2232                 goto sqlite_fail;
   2233             }
   2234             goto next;
   2235         }
   2236         if (JS_IsString(val)) {
   2237             const char *cstr;
   2238             size_t cstr_len;
   2239             cstr = JS_ToCStringLen(ctx, &cstr_len, val);
   2240             if (!cstr) {
   2241                 goto fail;
   2242             }
   2243             if (SQLITE_OK != sqlite3_bind_text64(stmt, param_index, cstr,
   2244                                                   cstr_len, SQLITE_TRANSIENT,
   2245                                                   SQLITE_UTF8)) {
   2246                 JS_FreeCString(ctx, cstr);
   2247                 goto sqlite_fail;
   2248             }
   2249             JS_FreeCString(ctx, cstr);
   2250             goto next;
   2251         }
   2252         if (JS_IsNumber(val)) {
   2253             int64_t n;
   2254             if (0 != JS_ToInt64(ctx, &n, val)) {
   2255                 goto fail;
   2256             }
   2257             if (SQLITE_OK != sqlite3_bind_int64(stmt, param_index, n)) {
   2258                 goto sqlite_fail;
   2259             }
   2260             goto next;
   2261         }
   2262         if (JS_IsArrayBuffer(val)) {
   2263             uint8_t *data;
   2264             size_t size;
   2265             data = JS_GetArrayBuffer(ctx, &size, val);
   2266             if (!data) {
   2267                 goto fail;
   2268             }
   2269             if (SQLITE_OK != sqlite3_bind_blob64(stmt, param_index, data, size,
   2270                                                   SQLITE_TRANSIENT)) {
   2271                 goto sqlite_fail;
   2272             }
   2273             goto next;
   2274         }
   2275         JS_ThrowTypeError(ctx, "unable to bind, unsupported type for arg %s", key);
   2276         goto fail;
   2277 next:
   2278         JS_FreeCString(ctx, key);
   2279         key = NULL;
   2280         JS_FreeValue(ctx, val);
   2281         val = JS_UNDEFINED;
   2282     }
   2283 done:
   2284     for (i = 0; i < len; i++) {
   2285         JS_FreeAtom(ctx, tab[i].atom);
   2286     }
   2287     js_free(ctx, tab);
   2288     return retval;
   2289 fail:
   2290     JS_FreeCString(ctx, key);
   2291     JS_FreeValue(ctx, val);
   2292     retval = -1;
   2293     goto done;
   2294 sqlite_fail:
   2295     throw_sqlite3_error(ctx, sqlite3_db_handle(stmt));
   2296     goto fail;
   2297 }
   2298 
   2299 
   2300 static JSValue js_sqlite3_stmt_run(JSContext *ctx, JSValue this_val,
   2301                                               int argc, JSValueConst *argv)
   2302 {
   2303     JSValue ret_val = JS_UNDEFINED;
   2304     JSValue stmt_handle;
   2305     sqlite3_stmt *stmt;
   2306     sqlite3 *db;
   2307     int sqlret;
   2308 
   2309     if (argc < 1 ||
   2310         JS_GetClassID(argv[0]) != js_sqlite3_statement_class_id) {
   2311         return JS_ThrowTypeError(ctx, "expected sqlite3 statement handle");
   2312     }
   2313     stmt_handle = argv[0];
   2314 
   2315     stmt = JS_GetOpaque(stmt_handle, js_sqlite3_statement_class_id);
   2316     if (!stmt) {
   2317         ret_val = JS_ThrowTypeError(ctx, "invalid sqlite3 statement handle");
   2318         goto done;
   2319     }
   2320     db = sqlite3_db_handle(stmt);
   2321     // Reset is not strictly necessary, we do it anyway just to be safe
   2322     sqlret = sqlite3_reset(stmt);
   2323     if (SQLITE_OK != sqlret) {
   2324         fprintf(stderr, "sqlite3_reset failed (in stmt_run): %s\n", sqlite3_errmsg(db));
   2325         ret_val = throw_sqlite3_error(ctx, db);
   2326         goto done;
   2327     }
   2328     sqlret = sqlite3_clear_bindings(stmt);
   2329     if (SQLITE_OK != sqlret) {
   2330         ret_val = throw_sqlite3_error(ctx, db);
   2331         goto done;
   2332     }
   2333     if (argc > 1) {
   2334         if (0 != bind_from_object(ctx, stmt, argv[1])) {
   2335             ret_val = JS_EXCEPTION;
   2336             goto done;
   2337         }
   2338     }
   2339     while (1) {
   2340         sqlret = sqlite3_step(stmt);
   2341         switch (sqlret) {
   2342         case SQLITE_ROW:
   2343             break;
   2344         case SQLITE_DONE: {
   2345             JSValue rowid_val;
   2346             ret_val = JS_NewObject(ctx);
   2347             sqlite3_int64 rowid = sqlite3_last_insert_rowid(db);
   2348             if (rowid >= MIN_SAFE_INTEGER && rowid <= MAX_SAFE_INTEGER) {
   2349                 rowid_val = JS_NewInt64(ctx, rowid);
   2350             } else {
   2351                 rowid_val = JS_NewBigInt64(ctx, rowid);
   2352             }
   2353             JS_SetPropertyStr(ctx, ret_val, "lastInsertRowid", rowid_val);
   2354             sqlret = sqlite3_reset(stmt);
   2355             if (SQLITE_OK != sqlret) {
   2356                 fprintf(stderr, "sqlite3_reset failed (in stmt_run after SQLITE_DONE): %s\n", sqlite3_errmsg(db));
   2357                 JS_FreeValue(ctx, ret_val);
   2358                 ret_val = throw_sqlite3_error(ctx, db);
   2359                 goto done;
   2360             }
   2361             goto done;
   2362         }
   2363         default:
   2364             ret_val = throw_sqlite3_error(ctx, db);
   2365             sqlite3_reset(stmt);
   2366             goto done;
   2367         }
   2368     }
   2369 done:
   2370     return ret_val;
   2371 }
   2372 
   2373 
   2374 static int extract_result_row(JSContext *ctx, sqlite3_stmt *stmt, JSValueConst target)
   2375 {
   2376     int colcount;
   2377     int i;
   2378 
   2379     colcount = sqlite3_column_count(stmt);
   2380 
   2381     for (i = 0; i < colcount; i++) {
   2382         const char *colname = sqlite3_column_name(stmt, i);
   2383         int coltype = sqlite3_column_type(stmt, i);
   2384         switch (coltype) {
   2385         case SQLITE_INTEGER: {
   2386             int64_t val = sqlite3_column_int64(stmt, i);
   2387             if (val > MAX_SAFE_INTEGER || val < MIN_SAFE_INTEGER) {
   2388                 JS_SetPropertyStr(ctx, target, colname, JS_NewBigInt64(ctx, val));
   2389             } else {
   2390                 JS_SetPropertyStr(ctx, target, colname, JS_NewInt64(ctx, val));
   2391             }
   2392             break;
   2393         }
   2394         case SQLITE_FLOAT: {
   2395             double val = sqlite3_column_double(stmt, i);
   2396             JS_SetPropertyStr(ctx, target, colname, JS_NewFloat64(ctx, val));
   2397             break;
   2398         }
   2399         case SQLITE_BLOB: {
   2400             JSValue abuf;
   2401             const uint8_t *blobdata = sqlite3_column_blob(stmt, i);
   2402             size_t bloblen = sqlite3_column_bytes(stmt, i);
   2403             abuf = JS_NewArrayBufferCopy(ctx, blobdata, bloblen);
   2404             JS_SetPropertyStr(ctx, target, colname, JS_NewTypedArraySimple(ctx, abuf, 1));
   2405             break;
   2406         }
   2407         case SQLITE_NULL:
   2408             JS_SetPropertyStr(ctx, target, colname, JS_NULL);
   2409             break;
   2410         case SQLITE_TEXT: {
   2411             const char *text = (const char *) sqlite3_column_text(stmt, i);
   2412             size_t text_len = sqlite3_column_bytes(stmt, i);
   2413             JS_SetPropertyStr(ctx, target, colname,
   2414                               JS_NewStringLen(ctx, text, text_len));
   2415             break;
   2416         }
   2417         default:
   2418             JS_ThrowInternalError(ctx, "unexpected type from DB");
   2419             return -1;
   2420         }
   2421     }
   2422     return 0;
   2423 }
   2424 
   2425 
   2426 static JSValue js_sqlite3_stmt_get_all(JSContext *ctx, JSValue this_val,
   2427                                               int argc, JSValueConst *argv)
   2428 {
   2429     JSValue ret_val = JS_UNDEFINED;
   2430     JSValue stmt_handle;
   2431     sqlite3_stmt *stmt;
   2432     sqlite3 *db;
   2433     int sqlret;
   2434     JSValue rows_array = JS_UNDEFINED;
   2435 
   2436     if (argc < 1 ||
   2437         JS_GetClassID(argv[0]) != js_sqlite3_statement_class_id) {
   2438         return JS_ThrowTypeError(ctx, "expected sqlite3 statement handle");
   2439     }
   2440     stmt_handle = argv[0];
   2441 
   2442     stmt = JS_GetOpaque(stmt_handle, js_sqlite3_statement_class_id);
   2443     if (!stmt) {
   2444         ret_val = JS_ThrowTypeError(ctx, "invalid sqlite3 statement handle");
   2445         goto done;
   2446     }
   2447     db = sqlite3_db_handle(stmt);
   2448     sqlret = sqlite3_reset(stmt);
   2449     if (SQLITE_OK != sqlret) {
   2450         fprintf(stderr, "sqlite3_reset failed (in stmt_get_all): %s\n", sqlite3_errmsg(db));
   2451         ret_val = throw_sqlite3_error(ctx, db);
   2452         goto done;
   2453     }
   2454     sqlret = sqlite3_clear_bindings(stmt);
   2455     if (SQLITE_OK != sqlret) {
   2456         ret_val = throw_sqlite3_error(ctx, db);
   2457         goto done;
   2458     }
   2459     if (argc > 1) {
   2460         if (0 != bind_from_object(ctx, stmt, argv[1])) {
   2461             ret_val = JS_EXCEPTION;
   2462             goto done;
   2463         }
   2464     }
   2465     rows_array = JS_NewArray(ctx);
   2466     while (1) {
   2467         sqlret = sqlite3_step(stmt);
   2468         switch (sqlret) {
   2469         case SQLITE_ROW: {
   2470             JSValue row_obj = JS_NewObject(ctx);
   2471             if (0 != extract_result_row(ctx, stmt, row_obj)) {
   2472                 goto fail;
   2473             }
   2474             qjs_array_append_new(ctx, rows_array, row_obj);
   2475             break;
   2476         }
   2477         case SQLITE_DONE: {
   2478             sqlret = sqlite3_reset(stmt);
   2479             if (SQLITE_OK != sqlret) {
   2480                 fprintf(stderr, "sqlite3_reset failed (in stmt_get_all after SQLITE_DONE): %s\n", sqlite3_errmsg(db));
   2481                 ret_val = throw_sqlite3_error(ctx, db);
   2482             } else {
   2483                 ret_val = JS_DupValue(ctx, rows_array);
   2484             }
   2485             goto done;
   2486         }
   2487         default:
   2488             ret_val = throw_sqlite3_error(ctx, db);
   2489             sqlite3_reset(stmt);
   2490             goto done;
   2491         }
   2492     }
   2493 done:
   2494     JS_FreeValue(ctx, rows_array);
   2495     return ret_val;
   2496 fail:
   2497     ret_val = JS_EXCEPTION;
   2498     goto done;
   2499 }
   2500 
   2501 static JSValue js_sqlite3_stmt_get_first(JSContext *ctx, JSValue this_val,
   2502                                               int argc, JSValueConst *argv)
   2503 {
   2504     JSValue ret_val = JS_UNDEFINED;
   2505     JSValue stmt_handle;
   2506     sqlite3_stmt *stmt;
   2507     sqlite3 *db;
   2508     int sqlret;
   2509 
   2510     if (argc < 1 ||
   2511         JS_GetClassID(argv[0]) != js_sqlite3_statement_class_id) {
   2512         return JS_ThrowTypeError(ctx, "expected sqlite3 statement handle");
   2513     }
   2514     stmt_handle = argv[0];
   2515 
   2516     stmt = JS_GetOpaque(stmt_handle, js_sqlite3_statement_class_id);
   2517     if (!stmt) {
   2518         ret_val = JS_ThrowTypeError(ctx, "invalid sqlite3 statement handle");
   2519         goto done;
   2520     }
   2521     db = sqlite3_db_handle(stmt);
   2522     sqlret = sqlite3_reset(stmt);
   2523     if (SQLITE_OK != sqlret) {
   2524         fprintf(stderr, "sqlite3_reset failed (in stmt_get_first): %s\n", sqlite3_errmsg(db));
   2525         ret_val = throw_sqlite3_error(ctx, db);
   2526         goto done;
   2527     }
   2528     sqlret = sqlite3_clear_bindings(stmt);
   2529     if (SQLITE_OK != sqlret) {
   2530         ret_val = throw_sqlite3_error(ctx, db);
   2531         goto done;
   2532     }
   2533     if (argc > 1) {
   2534         if (0 != bind_from_object(ctx, stmt, argv[1])) {
   2535             ret_val = JS_EXCEPTION;
   2536             goto done;
   2537         }
   2538     }
   2539     while (1) {
   2540         sqlret = sqlite3_step(stmt);
   2541         switch (sqlret) {
   2542         case SQLITE_ROW: {
   2543             JSValue row_obj = JS_NewObject(ctx);
   2544             if (0 != extract_result_row(ctx, stmt, row_obj)) {
   2545                 goto fail;
   2546             }
   2547             ret_val = row_obj;
   2548             goto reset;
   2549         }
   2550         case SQLITE_DONE: {
   2551             ret_val = JS_UNDEFINED;
   2552             goto reset;
   2553         }
   2554         default:
   2555             ret_val = throw_sqlite3_error(ctx, db);
   2556             sqlite3_reset(stmt);
   2557             goto done;
   2558         }
   2559     }
   2560 reset:
   2561     sqlret = sqlite3_reset(stmt);
   2562     if (SQLITE_OK != sqlret) {
   2563         fprintf(stderr, "sqlite3_reset failed (in stmt_get_first): %s\n", sqlite3_errmsg(db));
   2564         JS_FreeValue(ctx, ret_val);
   2565         ret_val = throw_sqlite3_error(ctx, db);
   2566     }
   2567 done:
   2568     return ret_val;
   2569 fail:
   2570     ret_val = JS_EXCEPTION;
   2571     goto reset;
   2572 }
   2573 
   2574 
   2575 static const JSCFunctionListEntry tart_talercrypto_funcs[] = {
   2576     JS_PROP_INT32_DEF("apiVersion", TART_API_VERSION, 0),
   2577     JS_CFUNC_DEF("structuredClone", 1, js_structured_clone),
   2578     JS_CFUNC_DEF("encodeUtf8", 1, js_encode_utf8),
   2579     JS_CFUNC_DEF("crashForDebug", 0, js_crash_for_debug),
   2580     JS_CFUNC_DEF("decodeUtf8", 1, js_decode_utf8),
   2581     JS_CFUNC_DEF("randomBytes", 1, js_random_bytes),
   2582     JS_CFUNC_DEF("encodeCrock", 1, js_talercrypto_encode_crock),
   2583     JS_CFUNC_DEF("decodeCrock", 1, js_talercrypto_decode_crock),
   2584     JS_CFUNC_DEF("hash", 1, js_talercrypto_hash),
   2585     JS_CFUNC_DEF("hashStateInit", 0, js_talercrypto_hash_state_init),
   2586     JS_CFUNC_DEF("hashStateUpdate", 2, js_talercrypto_hash_state_update),
   2587     JS_CFUNC_DEF("hashStateFinish", 1, js_talercrypto_hash_state_finish),
   2588     JS_CFUNC_DEF("hashArgon2id", 5, js_talercrypto_hash_argon2id),
   2589     JS_CFUNC_DEF("eddsaGetPublic", 1, js_talercrypto_eddsa_key_get_public),
   2590     JS_CFUNC_DEF("ecdheGetPublic", 1, js_talercrypto_ecdhe_key_get_public),
   2591     JS_CFUNC_DEF("eddsaSign", 2, js_talercrypto_eddsa_sign),
   2592     JS_CFUNC_DEF("eddsaVerify", 3, js_talercrypto_eddsa_verify),
   2593     JS_CFUNC_DEF("kdf", 3, js_talercrypto_kdf),
   2594     JS_CFUNC_DEF("keyExchangeEcdhEddsa", 2, js_talercrypto_kx_ecdh_eddsa),
   2595     JS_CFUNC_DEF("keyExchangeEddsaEcdh", 2, js_talercrypto_kx_eddsa_ecdh),
   2596     JS_CFUNC_DEF("rsaBlind", 3, js_talercrypto_rsa_blind),
   2597     JS_CFUNC_DEF("rsaUnblind", 3, js_talercrypto_rsa_unblind),
   2598     JS_CFUNC_DEF("rsaVerify", 3, js_talercrypto_rsa_verify),
   2599     JS_CFUNC_DEF("sqlite3Open", 2, js_sqlite3_open),
   2600     JS_CFUNC_DEF("sqlite3Close", 1, js_sqlite3_close),
   2601     JS_CFUNC_DEF("sqlite3Prepare", 2, js_sqlite3_prepare),
   2602     JS_CFUNC_DEF("sqlite3Finalize", 1, js_sqlite3_finalize),
   2603     JS_CFUNC_DEF("sqlite3Exec", 2, js_sqlite3_exec),
   2604     JS_CFUNC_DEF("sqlite3StmtRun", 2, js_sqlite3_stmt_run),
   2605     JS_CFUNC_DEF("sqlite3StmtGetFirst", 2, js_sqlite3_stmt_get_first),
   2606     JS_CFUNC_DEF("sqlite3StmtGetAll", 2, js_sqlite3_stmt_get_all),
   2607 };
   2608 
   2609 static pthread_once_t tart_class_ids_once = PTHREAD_ONCE_INIT;
   2610 
   2611 static void tart_init_class_ids(void)
   2612 {
   2613     JS_NewClassID(&js_hash_state_class_id);
   2614     JS_NewClassID(&js_sqlite3_database_class_id);
   2615     JS_NewClassID(&js_sqlite3_statement_class_id);
   2616     JS_NewClassID(&js_sqlite3_error_class_id);
   2617 }
   2618 
   2619 static int tart_talercrypto_init(JSContext *ctx, JSModuleDef *m)
   2620 {
   2621     JSValue error_class;
   2622     JSValue error_base_proto;
   2623     JSValue error_constructor;
   2624     JSValue error_proto;
   2625     JSValue global;
   2626 
   2627     if (0 != pthread_once(&tart_class_ids_once, tart_init_class_ids)) {
   2628         return -1;
   2629     }
   2630     if (0 != JS_NewClass(JS_GetRuntime(ctx), js_hash_state_class_id,
   2631                          &js_hash_state_class) ||
   2632         0 != JS_NewClass(JS_GetRuntime(ctx), js_sqlite3_database_class_id,
   2633                          &js_sqlite3_database_class) ||
   2634         0 != JS_NewClass(JS_GetRuntime(ctx), js_sqlite3_statement_class_id,
   2635                          &js_sqlite3_statement_class) ||
   2636         0 != JS_NewClass(JS_GetRuntime(ctx), js_sqlite3_error_class_id,
   2637                          &js_sqlite3_error_class)) {
   2638         return -1;
   2639     }
   2640 
   2641     global = JS_GetGlobalObject(ctx);
   2642     error_class = JS_GetPropertyStr(ctx, global, "Error");
   2643     JS_FreeValue(ctx, global);
   2644     if (JS_IsException(error_class)) {
   2645         return -1;
   2646     }
   2647     error_base_proto = JS_GetPropertyStr(ctx, error_class, "prototype");
   2648     JS_FreeValue(ctx, error_class);
   2649     if (JS_IsException(error_base_proto)) {
   2650         return -1;
   2651     }
   2652     error_proto = JS_NewObjectProto(ctx, error_base_proto);
   2653     JS_FreeValue(ctx, error_base_proto);
   2654     if (JS_IsException(error_proto)) {
   2655         return -1;
   2656     }
   2657     if (JS_DefinePropertyValueStr(
   2658             ctx,
   2659             error_proto,
   2660             "name",
   2661             JS_NewString(ctx, "Sqlite3Error"),
   2662             JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE) < 0) {
   2663         JS_FreeValue(ctx, error_proto);
   2664         return -1;
   2665     }
   2666 
   2667     error_constructor = JS_NewCFunction2(ctx,
   2668                                          js_sqlite3_error_constructor,
   2669                                          "Sqlite3Error",
   2670                                          1,
   2671                                          JS_CFUNC_constructor,
   2672                                          0);
   2673     if (JS_IsException(error_constructor)) {
   2674         JS_FreeValue(ctx, error_proto);
   2675         return -1;
   2676     }
   2677     if (JS_SetConstructor(ctx, error_constructor, error_proto) < 0) {
   2678         JS_FreeValue(ctx, error_constructor);
   2679         JS_FreeValue(ctx, error_proto);
   2680         return -1;
   2681     }
   2682     JS_SetClassProto(ctx, js_sqlite3_error_class_id, error_proto);
   2683 
   2684     if (JS_SetModuleExportList(ctx, m, tart_talercrypto_funcs,
   2685                                countof(tart_talercrypto_funcs)) < 0) {
   2686         JS_FreeValue(ctx, error_constructor);
   2687         return -1;
   2688     }
   2689     return JS_SetModuleExport(ctx, m, "Sqlite3Error", error_constructor);
   2690 }
   2691 
   2692 JSModuleDef *tart_init_module_talercrypto(JSContext *ctx, const char *module_name)
   2693 {
   2694     JSModuleDef *m;
   2695     m = JS_NewCModule(ctx, module_name, tart_talercrypto_init);
   2696     if (!m) {
   2697         return NULL;
   2698     }
   2699     JS_AddModuleExportList(ctx, m, tart_talercrypto_funcs,
   2700                            countof(tart_talercrypto_funcs));
   2701     JS_AddModuleExport(ctx, m, "Sqlite3Error");
   2702     return m;
   2703 }