quickjs-tart

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

tart_module.c (70022B)


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