gnunet-svn
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[taler-donau] 01/03: [deps] add json from exchange (can be removed again


From: gnunet
Subject: [taler-donau] 01/03: [deps] add json from exchange (can be removed again if json is linked against json from exchange)
Date: Sat, 06 Jan 2024 23:18:10 +0100

This is an automated email from the git hooks/post-receive script.

pius-loosli pushed a commit to branch master
in repository donau.

commit afc7557882e41c13ae1c59f29b2292eb696a87dc
Author: Pius Loosli <loosp2@bfh.ch>
AuthorDate: Sat Jan 6 21:36:14 2024 +0100

    [deps] add json from exchange (can be removed again if json is linked 
against json from exchange)
---
 src/json/Makefile.am   |    5 +-
 src/json/json.c        |  763 ++++++++++++++++++++++-
 src/json/json_helper.c | 1621 ++++++++++++++++++++++++++++++++++++++++++++++++
 src/json/json_pack.c   |  324 ++++++++++
 4 files changed, 2710 insertions(+), 3 deletions(-)

diff --git a/src/json/Makefile.am b/src/json/Makefile.am
index d952331..8806c67 100644
--- a/src/json/Makefile.am
+++ b/src/json/Makefile.am
@@ -10,7 +10,10 @@ lib_LTLIBRARIES = \
   libtalerjson.la
 
 libtalerjson_la_SOURCES = \
-  json.c 
+  json.c \
+  json_helper.c \
+  json_pack.c
+
 libtalerjson_la_LDFLAGS = \
   -version-info 1:0:1 \
   -no-undefined
diff --git a/src/json/json.c b/src/json/json.c
index e71577b..8c2415c 100644
--- a/src/json/json.c
+++ b/src/json/json.c
@@ -1,6 +1,6 @@
 /*
   This file is part of TALER
-  Copyright (C) 2023 Taler Systems SA
+  Copyright (C) 2024 Taler Systems SA
 
   TALER is free software; you can redistribute it and/or modify it under the
   terms of the GNU General Public License as published by the Free Software
@@ -21,9 +21,768 @@
  */
 #include "taler/platform.h"
 #include <gnunet/gnunet_util_lib.h>
-#include <taler/taler_util.h>
+#include "taler/taler_util.h"
 #include "taler/taler_json_lib.h"
 #include <unistr.h>
 
 
+/**
+ * Check if @a json contains a 'real' value anywhere.
+ *
+ * @param json json to check
+ * @return true if a real is in it somewhere
+ */
+static bool
+contains_real (const json_t *json)
+{
+  if (json_is_real (json))
+    return true;
+  if (json_is_object (json))
+  {
+    json_t *member;
+    const char *name;
+
+    json_object_foreach ((json_t *) json, name, member)
+    if (contains_real (member))
+      return true;
+    return false;
+  }
+  if (json_is_array (json))
+  {
+    json_t *member;
+    size_t index;
+
+    json_array_foreach ((json_t *) json, index, member)
+    if (contains_real (member))
+      return true;
+    return false;
+  }
+  return false;
+}
+
+
+/**
+ * Dump the @a json to a string and hash it.
+ *
+ * @param json value to hash
+ * @param salt salt value to include when using HKDF,
+ *        NULL to not use any salt and to use SHA512
+ * @param[out] hc where to store the hash
+ * @return #GNUNET_OK on success,
+ *         #GNUNET_NO if @a json was not hash-able
+ *         #GNUNET_SYSERR on failure
+ */
+static enum GNUNET_GenericReturnValue
+dump_and_hash (const json_t *json,
+               const char *salt,
+               struct GNUNET_HashCode *hc)
+{
+  char *wire_enc;
+  size_t len;
+
+  if (NULL == json)
+  {
+    GNUNET_break_op (0);
+    return GNUNET_NO;
+  }
+  if (contains_real (json))
+  {
+    GNUNET_break_op (0);
+    return GNUNET_NO;
+  }
+  if (NULL == (wire_enc = json_dumps (json,
+                                      JSON_ENCODE_ANY
+                                      | JSON_COMPACT
+                                      | JSON_SORT_KEYS)))
+  {
+    GNUNET_break (0);
+    return GNUNET_SYSERR;
+  }
+  len = TALER_rfc8785encode (&wire_enc);
+  if (NULL == salt)
+  {
+    GNUNET_CRYPTO_hash (wire_enc,
+                        len,
+                        hc);
+  }
+  else
+  {
+    if (GNUNET_YES !=
+        GNUNET_CRYPTO_kdf (hc,
+                           sizeof (*hc),
+                           salt,
+                           strlen (salt) + 1,
+                           wire_enc,
+                           len,
+                           NULL,
+                           0))
+    {
+      GNUNET_break (0);
+      free (wire_enc);
+      return GNUNET_SYSERR;
+    }
+  }
+  free (wire_enc);
+  return GNUNET_OK;
+}
+
+
+/**
+ * Replace "forgettable" parts of a JSON object with their salted hash.
+ *
+ * @param[in] in some JSON value
+ * @param[out] out resulting JSON value
+ * @return #GNUNET_OK on success,
+ *         #GNUNET_NO if @a json was not hash-able
+ *         #GNUNET_SYSERR on failure
+ */
+static enum GNUNET_GenericReturnValue
+forget (const json_t *in,
+        json_t **out)
+{
+  if (json_is_real (in))
+  {
+    /* floating point is not allowed! */
+    GNUNET_break_op (0);
+    return GNUNET_NO;
+  }
+  if (json_is_array (in))
+  {
+    /* array is a JSON array */
+    size_t index;
+    json_t *value;
+    json_t *ret;
+
+    ret = json_array ();
+    if (NULL == ret)
+    {
+      GNUNET_break (0);
+      return GNUNET_SYSERR;
+    }
+    json_array_foreach (in, index, value) {
+      enum GNUNET_GenericReturnValue iret;
+      json_t *t;
+
+      iret = forget (value,
+                     &t);
+      if (GNUNET_OK != iret)
+      {
+        json_decref (ret);
+        return iret;
+      }
+      if (0 != json_array_append_new (ret,
+                                      t))
+      {
+        GNUNET_break (0);
+        json_decref (ret);
+        return GNUNET_SYSERR;
+      }
+    }
+    *out = ret;
+    return GNUNET_OK;
+  }
+  if (json_is_object (in))
+  {
+    json_t *ret;
+    const char *key;
+    json_t *value;
+    json_t *fg;
+    json_t *rx;
+
+    fg = json_object_get (in,
+                          "$forgettable");
+    rx = json_object_get (in,
+                          "$forgotten");
+    if (NULL != rx)
+    {
+      rx = json_deep_copy (rx); /* should be shallow
+                                   by structure, but
+                                   deep copy is safer */
+      if (NULL == rx)
+      {
+        GNUNET_break (0);
+        return GNUNET_SYSERR;
+      }
+    }
+    ret = json_object ();
+    if (NULL == ret)
+    {
+      GNUNET_break (0);
+      return GNUNET_SYSERR;
+    }
+    json_object_foreach ((json_t*) in, key, value) {
+      json_t *t;
+      json_t *salt;
+      enum GNUNET_GenericReturnValue iret;
+
+      if (fg == value)
+        continue; /* skip! */
+      if (rx == value)
+        continue; /* skip! */
+      if ( (NULL != rx) &&
+           (NULL !=
+            json_object_get (rx,
+                             key)) )
+      {
+        (void) json_object_del (ret,
+                                key);
+        continue; /* already forgotten earlier */
+      }
+      iret = forget (value,
+                     &t);
+      if (GNUNET_OK != iret)
+      {
+        json_decref (ret);
+        json_decref (rx);
+        return iret;
+      }
+      if ( (NULL != fg) &&
+           (NULL != (salt = json_object_get (fg,
+                                             key))) )
+      {
+        /* 't' is to be forgotten! */
+        struct GNUNET_HashCode hc;
+
+        if (! json_is_string (salt))
+        {
+          GNUNET_break_op (0);
+          json_decref (ret);
+          json_decref (rx);
+          json_decref (t);
+          return GNUNET_NO;
+        }
+        iret = dump_and_hash (t,
+                              json_string_value (salt),
+                              &hc);
+        if (GNUNET_OK != iret)
+        {
+          json_decref (ret);
+          json_decref (rx);
+          json_decref (t);
+          return iret;
+        }
+        json_decref (t);
+        /* scrub salt */
+        if (0 !=
+            json_object_del (fg,
+                             key))
+        {
+          GNUNET_break_op (0);
+          json_decref (ret);
+          json_decref (rx);
+          return GNUNET_NO;
+        }
+        if (NULL == rx)
+          rx = json_object ();
+        if (NULL == rx)
+        {
+          GNUNET_break (0);
+          json_decref (ret);
+          return GNUNET_SYSERR;
+        }
+        if (0 !=
+            json_object_set_new (rx,
+                                 key,
+                                 GNUNET_JSON_from_data_auto (&hc)))
+        {
+          GNUNET_break (0);
+          json_decref (ret);
+          json_decref (rx);
+          return GNUNET_SYSERR;
+        }
+      }
+      else
+      {
+        /* 't' to be used without 'forgetting' */
+        if (0 !=
+            json_object_set_new (ret,
+                                 key,
+                                 t))
+        {
+          GNUNET_break (0);
+          json_decref (ret);
+          json_decref (rx);
+          return GNUNET_SYSERR;
+        }
+      }
+    } /* json_object_foreach */
+    if ( (NULL != rx) &&
+         (0 !=
+          json_object_set_new (ret,
+                               "$forgotten",
+                               rx)) )
+    {
+      GNUNET_break (0);
+      json_decref (ret);
+      return GNUNET_SYSERR;
+    }
+    *out = ret;
+    return GNUNET_OK;
+  }
+  *out = json_incref ((json_t *) in);
+  return GNUNET_OK;
+}
+
+
+enum GNUNET_GenericReturnValue
+TALER_JSON_contract_hash (const json_t *json,
+                          struct TALER_PrivateContractHashP *hc)
+{
+  enum GNUNET_GenericReturnValue ret;
+  json_t *cjson;
+  json_t *dc;
+
+  dc = json_deep_copy (json);
+  ret = forget (dc,
+                &cjson);
+  json_decref (dc);
+  if (GNUNET_OK != ret)
+    return ret;
+  ret = dump_and_hash (cjson,
+                       NULL,
+                       &hc->hash);
+  json_decref (cjson);
+  return ret;
+}
+
+
+enum GNUNET_GenericReturnValue
+TALER_JSON_contract_mark_forgettable (json_t *json,
+                                      const char *field)
+{
+  json_t *fg;
+  struct GNUNET_ShortHashCode salt;
+
+  if (! json_is_object (json))
+  {
+    GNUNET_break (0);
+    return GNUNET_SYSERR;
+  }
+  /* check field name is legal for forgettable field */
+  for (const char *f = field; '\0' != *f; f++)
+  {
+    char c = *f;
+
+    if ( (c >= 'a') && (c <= 'z') )
+      continue;
+    if ( (c >= 'A') && (c <= 'Z') )
+      continue;
+    if ( (c >= '0') && (c <= '9') )
+      continue;
+    if ('_' == c)
+      continue;
+    GNUNET_break (0);
+    return GNUNET_SYSERR;
+  }
+  if (NULL == json_object_get (json,
+                               field))
+  {
+    /* field must exist */
+    GNUNET_break (0);
+    return GNUNET_SYSERR;
+  }
+  fg = json_object_get (json,
+                        "$forgettable");
+  if (NULL == fg)
+  {
+    fg = json_object ();
+    if (0 !=
+        json_object_set_new (json,
+                             "$forgettable",
+                             fg))
+    {
+      GNUNET_break (0);
+      return GNUNET_SYSERR;
+    }
+  }
+
+  GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_NONCE,
+                              &salt,
+                              sizeof (salt));
+  if (0 !=
+      json_object_set_new (fg,
+                           field,
+                           GNUNET_JSON_from_data_auto (&salt)))
+  {
+    GNUNET_break (0);
+    return GNUNET_SYSERR;
+  }
+  return GNUNET_OK;
+}
+
+
+enum GNUNET_GenericReturnValue
+TALER_JSON_contract_part_forget (json_t *json,
+                                 const char *field)
+{
+  json_t *fg;
+  const json_t *part;
+  json_t *fp;
+  json_t *rx;
+  struct GNUNET_HashCode hc;
+  const char *salt;
+  enum GNUNET_GenericReturnValue ret;
+
+  if (! json_is_object (json))
+  {
+    GNUNET_break (0);
+    return GNUNET_SYSERR;
+  }
+  if (NULL == (part = json_object_get (json,
+                                       field)))
+  {
+    GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+                "Did not find field `%s' we were asked to forget\n",
+                field);
+    return GNUNET_SYSERR;
+  }
+  fg = json_object_get (json,
+                        "$forgettable");
+  if (NULL == fg)
+  {
+    GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+                "Did not find '$forgettable' attribute trying to forget field 
`%s'\n",
+                field);
+    return GNUNET_SYSERR;
+  }
+  rx = json_object_get (json,
+                        "$forgotten");
+  if (NULL == rx)
+  {
+    rx = json_object ();
+    if (0 !=
+        json_object_set_new (json,
+                             "$forgotten",
+                             rx))
+    {
+      GNUNET_break (0);
+      return GNUNET_SYSERR;
+    }
+  }
+  if (NULL !=
+      json_object_get (rx,
+                       field))
+  {
+    if (! json_is_null (json_object_get (json,
+                                         field)))
+    {
+      GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+                  "Field `%s' market as forgotten, but still exists!\n",
+                  field);
+      return GNUNET_SYSERR;
+    }
+    GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+                "Already forgot field `%s'\n",
+                field);
+    return GNUNET_NO;
+  }
+  salt = json_string_value (json_object_get (fg,
+                                             field));
+  if (NULL == salt)
+  {
+    GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+                "Did not find required salt to forget field `%s'\n",
+                field);
+    return GNUNET_SYSERR;
+  }
+
+  /* need to recursively forget to compute 'hc' */
+  ret = forget (part,
+                &fp);
+  if (GNUNET_OK != ret)
+    return ret;
+  if (GNUNET_OK !=
+      dump_and_hash (fp,
+                     salt,
+                     &hc))
+  {
+    json_decref (fp);
+    GNUNET_break (0);
+    return GNUNET_SYSERR;
+  }
+  json_decref (fp);
+  /* drop salt */
+  if (0 !=
+      json_object_del (fg,
+                       field))
+  {
+    json_decref (fp);
+    GNUNET_break (0);
+    return GNUNET_SYSERR;
+  }
+
+  /* remember field as 'forgotten' */
+  if (0 !=
+      json_object_set_new (rx,
+                           field,
+                           GNUNET_JSON_from_data_auto (&hc)))
+  {
+    GNUNET_break (0);
+    return GNUNET_SYSERR;
+  }
+  /* finally, set 'forgotten' field to null */
+  if (0 !=
+      json_object_del (json,
+                       field))
+  {
+    GNUNET_break (0);
+    return GNUNET_SYSERR;
+  }
+  return GNUNET_OK;
+}
+
+
+/**
+ * Parse a json path.
+ *
+ * @param obj the object that the path is relative to.
+ * @param prev the parent of @e obj.
+ * @param path the path to parse.
+ * @param cb the callback to call, if we get to the end of @e path.
+ * @param cb_cls the closure for the callback.
+ * @return #GNUNET_OK on success, #GNUNET_SYSERR if @e path is malformed.
+ */
+static enum GNUNET_GenericReturnValue
+parse_path (json_t *obj,
+            json_t *prev,
+            const char *path,
+            TALER_JSON_ExpandPathCallback cb,
+            void *cb_cls)
+{
+  char *id = GNUNET_strdup (path);
+  char *next_id = strchr (id,
+                          '.');
+  char *next_path;
+  char *bracket;
+  json_t *next_obj = NULL;
+  char *next_dot;
+
+  GNUNET_assert (NULL != id); /* make stupid compiler happy */
+  if (NULL == next_id)
+  {
+    cb (cb_cls,
+        id,
+        prev);
+    GNUNET_free (id);
+    return GNUNET_OK;
+  }
+  bracket = strchr (next_id,
+                    '[');
+  *next_id = '\0';
+  next_id++;
+  next_path = GNUNET_strdup (next_id);
+  next_dot = strchr (next_id,
+                     '.');
+  if (NULL != next_dot)
+    *next_dot = '\0';
+  /* If this is the first time this is called, make sure id is "$" */
+  if ( (NULL == prev) &&
+       (0 != strcmp (id,
+                     "$")))
+  {
+    GNUNET_free (id);
+    GNUNET_free (next_path);
+    return GNUNET_SYSERR;
+  }
+
+  /* Check for bracketed indices */
+  if (NULL != bracket)
+  {
+    char *end_bracket = strchr (bracket,
+                                ']');
+    if (NULL == end_bracket)
+    {
+      GNUNET_free (id);
+      GNUNET_free (next_path);
+      return GNUNET_SYSERR;
+    }
+    *end_bracket = '\0';
+
+    *bracket = '\0';
+    bracket++;
+
+    json_t *array = json_object_get (obj,
+                                     next_id);
+    if (0 == strcmp (bracket,
+                     "*"))
+    {
+      size_t index;
+      json_t *value;
+      int ret = GNUNET_OK;
+
+      json_array_foreach (array, index, value) {
+        ret = parse_path (value,
+                          obj,
+                          next_path,
+                          cb,
+                          cb_cls);
+        if (GNUNET_OK != ret)
+        {
+          GNUNET_free (id);
+          GNUNET_free (next_path);
+          return ret;
+        }
+      }
+    }
+    else
+    {
+      unsigned int index;
+      char dummy;
+
+      if (1 != sscanf (bracket,
+                       "%u%c",
+                       &index,
+                       &dummy))
+      {
+        GNUNET_free (id);
+        GNUNET_free (next_path);
+        return GNUNET_SYSERR;
+      }
+      next_obj = json_array_get (array,
+                                 index);
+    }
+  }
+  else
+  {
+    /* No brackets, so just fetch the object by name */
+    next_obj = json_object_get (obj,
+                                next_id);
+  }
+
+  if (NULL != next_obj)
+  {
+    int ret = parse_path (next_obj,
+                          obj,
+                          next_path,
+                          cb,
+                          cb_cls);
+    GNUNET_free (id);
+    GNUNET_free (next_path);
+    return ret;
+  }
+  GNUNET_free (id);
+  GNUNET_free (next_path);
+  return GNUNET_OK;
+}
+
+
+enum GNUNET_GenericReturnValue
+TALER_JSON_expand_path (json_t *json,
+                        const char *path,
+                        TALER_JSON_ExpandPathCallback cb,
+                        void *cb_cls)
+{
+  return parse_path (json,
+                     NULL,
+                     path,
+                     cb,
+                     cb_cls);
+}
+
+
+enum TALER_ErrorCode
+TALER_JSON_get_error_code (const json_t *json)
+{
+  const json_t *jc;
+
+  if (NULL == json)
+    return TALER_EC_GENERIC_INVALID_RESPONSE;
+  jc = json_object_get (json, "code");
+  /* The caller already knows that the JSON represents an error,
+     so we are dealing with a missing error code here.  */
+  if (NULL == jc)
+  {
+    GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+                "Expected Taler error code `code' in JSON, but field does not 
exist!\n");
+    return TALER_EC_INVALID;
+  }
+  if (json_is_integer (jc))
+    return (enum TALER_ErrorCode) json_integer_value (jc);
+  GNUNET_break_op (0);
+  return TALER_EC_INVALID;
+}
+
+
+const char *
+TALER_JSON_get_error_hint (const json_t *json)
+{
+  const json_t *jc;
+
+  if (NULL == json)
+    return NULL;
+  jc = json_object_get (json,
+                        "hint");
+  if (NULL == jc)
+    return NULL; /* no hint, is allowed */
+  if (! json_is_string (jc))
+  {
+    /* Hints must be strings */
+    GNUNET_break_op (0);
+    return NULL;
+  }
+  return json_string_value (jc);
+}
+
+
+enum TALER_ErrorCode
+TALER_JSON_get_error_code2 (const void *data,
+                            size_t data_size)
+{
+  json_t *json;
+  enum TALER_ErrorCode ec;
+  json_error_t err;
+
+  json = json_loadb (data,
+                     data_size,
+                     JSON_REJECT_DUPLICATES,
+                     &err);
+  if (NULL == json)
+    return TALER_EC_INVALID;
+  ec = TALER_JSON_get_error_code (json);
+  json_decref (json);
+  if (ec == TALER_EC_NONE)
+    return TALER_EC_INVALID;
+  return ec;
+}
+
+
+void
+TALER_deposit_policy_hash (const json_t *policy,
+                           struct TALER_ExtensionPolicyHashP *ech)
+{
+  GNUNET_assert (GNUNET_OK ==
+                 dump_and_hash (policy,
+                                "taler-extensions-policy",
+                                &ech->hash));
+}
+
+
+char *
+TALER_JSON_canonicalize (const json_t *input)
+{
+  char *wire_enc;
+
+  if (NULL == (wire_enc = json_dumps (input,
+                                      JSON_ENCODE_ANY
+                                      | JSON_COMPACT
+                                      | JSON_SORT_KEYS)))
+  {
+    GNUNET_break (0);
+    return NULL;
+  }
+  TALER_rfc8785encode (&wire_enc);
+  return wire_enc;
+}
+
+
+enum GNUNET_GenericReturnValue
+TALER_JSON_extensions_manifests_hash (const json_t *manifests,
+                                      struct TALER_ExtensionManifestsHashP 
*ech)
+{
+  return dump_and_hash (manifests,
+                        "taler-extensions-manifests",
+                        &ech->hash);
+}
+
+
 /* End of json/json.c */
diff --git a/src/json/json_helper.c b/src/json/json_helper.c
new file mode 100644
index 0000000..0126574
--- /dev/null
+++ b/src/json/json_helper.c
@@ -0,0 +1,1621 @@
+/*
+  This file is part of TALER
+  Copyright (C) 2014-2024 Taler Systems SA
+
+  TALER is free software; you can redistribute it and/or modify it under the
+  terms of the GNU General Public License as published by the Free Software
+  Foundation; either version 3, or (at your option) any later version.
+
+  TALER is distributed in the hope that it will be useful, but WITHOUT ANY
+  WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+  A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
+
+  You should have received a copy of the GNU General Public License along with
+  TALER; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>
+*/
+/**
+ * @file json/json_helper.c
+ * @brief helper functions to generate specifications to parse
+ *        Taler-specific JSON objects with libgnunetjson
+ * @author Sree Harsha Totakura <sreeharsha@totakura.in>
+ * @author Christian Grothoff
+ */
+#include "taler/platform.h"
+#include <gnunet/gnunet_util_lib.h>
+#include "taler/taler_util.h"
+#include "taler/taler_json_lib.h"
+
+
+/**
+ * Convert string value to numeric cipher value.
+ *
+ * @param cipher_s input string
+ * @return numeric cipher value
+ */
+static enum GNUNET_CRYPTO_BlindSignatureAlgorithm
+string_to_cipher (const char *cipher_s)
+{
+  if ((0 == strcasecmp (cipher_s,
+                        "RSA")) ||
+      (0 == strcasecmp (cipher_s,
+                        "RSA+age_restricted")))
+    return GNUNET_CRYPTO_BSA_RSA;
+  if ((0 == strcasecmp (cipher_s,
+                        "CS")) ||
+      (0 == strcasecmp (cipher_s,
+                        "CS+age_restricted")))
+    return GNUNET_CRYPTO_BSA_CS;
+  return GNUNET_CRYPTO_BSA_INVALID;
+}
+
+
+json_t *
+TALER_JSON_from_amount (const struct TALER_Amount *amount)
+{
+  char *amount_str = TALER_amount_to_string (amount);
+
+  GNUNET_assert (NULL != amount_str);
+  {
+    json_t *j = json_string (amount_str);
+
+    GNUNET_free (amount_str);
+    return j;
+  }
+}
+
+
+/**
+ * Parse given JSON object to Amount
+ *
+ * @param cls closure, expected currency, or NULL
+ * @param root the json object representing data
+ * @param[out] spec where to write the data
+ * @return #GNUNET_OK upon successful parsing; #GNUNET_SYSERR upon error
+ */
+static enum GNUNET_GenericReturnValue
+parse_amount (void *cls,
+              json_t *root,
+              struct GNUNET_JSON_Specification *spec)
+{
+  const char *currency = cls;
+  struct TALER_Amount *r_amount = spec->ptr;
+
+  (void) cls;
+  if (! json_is_string (root))
+  {
+    GNUNET_break_op (0);
+    return GNUNET_SYSERR;
+  }
+  if (GNUNET_OK !=
+      TALER_string_to_amount (json_string_value (root),
+                              r_amount))
+  {
+    GNUNET_break_op (0);
+    return GNUNET_SYSERR;
+  }
+  if ( (NULL != currency) &&
+       (0 !=
+        strcasecmp (currency,
+                    r_amount->currency)) )
+  {
+    GNUNET_break_op (0);
+    GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+                "Expected currency `%s', but amount used currency `%s' in 
field `%s'\n",
+                currency,
+                r_amount->currency,
+                spec->field);
+    return GNUNET_SYSERR;
+  }
+  return GNUNET_OK;
+}
+
+
+struct GNUNET_JSON_Specification
+TALER_JSON_spec_amount (const char *name,
+                        const char *currency,
+                        struct TALER_Amount *r_amount)
+{
+  struct GNUNET_JSON_Specification ret = {
+    .parser = &parse_amount,
+    .cleaner = NULL,
+    .cls = (void *) currency,
+    .field = name,
+    .ptr = r_amount,
+    .ptr_size = 0,
+    .size_ptr = NULL
+  };
+
+  GNUNET_assert (NULL != currency);
+  return ret;
+}
+
+
+struct GNUNET_JSON_Specification
+TALER_JSON_spec_amount_any (const char *name,
+                            struct TALER_Amount *r_amount)
+{
+  struct GNUNET_JSON_Specification ret = {
+    .parser = &parse_amount,
+    .cleaner = NULL,
+    .cls = NULL,
+    .field = name,
+    .ptr = r_amount,
+    .ptr_size = 0,
+    .size_ptr = NULL
+  };
+
+  return ret;
+}
+
+
+/**
+ * Parse given JSON object to currency spec.
+ *
+ * @param cls closure, NULL
+ * @param root the json object representing data
+ * @param[out] spec where to write the data
+ * @return #GNUNET_OK upon successful parsing; #GNUNET_SYSERR upon error
+ */
+static enum GNUNET_GenericReturnValue
+parse_cspec (void *cls,
+             json_t *root,
+             struct GNUNET_JSON_Specification *spec)
+{
+  struct TALER_CurrencySpecification *r_cspec = spec->ptr;
+  const char *currency = spec->cls;
+  const char *name;
+  uint32_t fid;
+  uint32_t fnd;
+  uint32_t ftzd;
+  const json_t *map;
+  struct GNUNET_JSON_Specification gspec[] = {
+    GNUNET_JSON_spec_string ("name",
+                             &name),
+    GNUNET_JSON_spec_uint32 ("num_fractional_input_digits",
+                             &fid),
+    GNUNET_JSON_spec_uint32 ("num_fractional_normal_digits",
+                             &fnd),
+    GNUNET_JSON_spec_uint32 ("num_fractional_trailing_zero_digits",
+                             &ftzd),
+    GNUNET_JSON_spec_object_const ("alt_unit_names",
+                                   &map),
+    GNUNET_JSON_spec_end ()
+  };
+  const char *emsg;
+  unsigned int eline;
+
+  memset (r_cspec->currency,
+          0,
+          sizeof (r_cspec->currency));
+  if (GNUNET_OK !=
+      GNUNET_JSON_parse (root,
+                         gspec,
+                         &emsg,
+                         &eline))
+  {
+    GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+                "Failed to parse %s at %u: %s\n",
+                spec[eline].field,
+                eline,
+                emsg);
+    GNUNET_break_op (0);
+    return GNUNET_SYSERR;
+  }
+  if (strlen (currency) >= TALER_CURRENCY_LEN)
+  {
+    GNUNET_break_op (0);
+    return GNUNET_SYSERR;
+  }
+  if ( (fid > TALER_AMOUNT_FRAC_LEN) ||
+       (fnd > TALER_AMOUNT_FRAC_LEN) ||
+       (ftzd > TALER_AMOUNT_FRAC_LEN) )
+  {
+    GNUNET_break_op (0);
+    return GNUNET_SYSERR;
+  }
+  if (GNUNET_OK !=
+      TALER_check_currency (currency))
+  {
+    GNUNET_break_op (0);
+    return GNUNET_SYSERR;
+  }
+  strcpy (r_cspec->currency,
+          currency);
+  if (GNUNET_OK !=
+      TALER_check_currency_scale_map (map))
+  {
+    GNUNET_break_op (0);
+    return GNUNET_SYSERR;
+  }
+  r_cspec->name = GNUNET_strdup (name);
+  r_cspec->map_alt_unit_names = json_incref ((json_t *) map);
+  return GNUNET_OK;
+}
+
+
+/**
+ * Cleanup data left from parsing encrypted contract.
+ *
+ * @param cls closure, NULL
+ * @param[out] spec where to free the data
+ */
+static void
+clean_cspec (void *cls,
+             struct GNUNET_JSON_Specification *spec)
+{
+  struct TALER_CurrencySpecification *cspec = spec->ptr;
+
+  (void) cls;
+  GNUNET_free (cspec->name);
+  json_decref (cspec->map_alt_unit_names);
+}
+
+
+struct GNUNET_JSON_Specification
+TALER_JSON_spec_currency_specification (
+  const char *name,
+  const char *currency,
+  struct TALER_CurrencySpecification *r_cspec)
+{
+  struct GNUNET_JSON_Specification ret = {
+    .parser = &parse_cspec,
+    .cleaner = &clean_cspec,
+    .cls = (void *) currency,
+    .field = name,
+    .ptr = r_cspec,
+    .ptr_size = sizeof (*r_cspec),
+    .size_ptr = NULL
+  };
+
+  memset (r_cspec,
+          0,
+          sizeof (*r_cspec));
+  return ret;
+}
+
+
+static enum GNUNET_GenericReturnValue
+parse_denomination_group (void *cls,
+                          json_t *root,
+                          struct GNUNET_JSON_Specification *spec)
+{
+  struct TALER_DenominationGroup *group = spec->ptr;
+  const char *cipher;
+  const char *currency = cls;
+  bool age_mask_missing = false;
+  bool has_age_restricted_suffix = false;
+  struct GNUNET_JSON_Specification gspec[] = {
+    GNUNET_JSON_spec_string ("cipher",
+                             &cipher),
+    TALER_JSON_spec_amount ("value",
+                            currency,
+                            &group->value),
+    TALER_JSON_SPEC_DENOM_FEES ("fee",
+                                currency,
+                                &group->fees),
+    GNUNET_JSON_spec_mark_optional (
+      GNUNET_JSON_spec_uint32 ("age_mask",
+                               &group->age_mask.bits),
+      &age_mask_missing),
+    GNUNET_JSON_spec_end ()
+  };
+  const char *emsg;
+  unsigned int eline;
+
+  if (GNUNET_OK !=
+      GNUNET_JSON_parse (root,
+                         gspec,
+                         &emsg,
+                         &eline))
+  {
+    GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+                "Failed to parse %s at %u: %s\n",
+                spec[eline].field,
+                eline,
+                emsg);
+    GNUNET_break_op (0);
+    return GNUNET_SYSERR;
+  }
+
+  group->cipher = string_to_cipher (cipher);
+  if (GNUNET_CRYPTO_BSA_INVALID == group->cipher)
+  {
+    GNUNET_break_op (0);
+    return GNUNET_SYSERR;
+  }
+
+  /* age_mask and suffix must be consistent */
+  has_age_restricted_suffix =
+    (NULL != strstr (cipher, "+age_restricted"));
+  if (has_age_restricted_suffix && age_mask_missing)
+  {
+    GNUNET_break_op (0);
+    return GNUNET_SYSERR;
+  }
+
+  if (age_mask_missing)
+    group->age_mask.bits = 0;
+
+  return GNUNET_OK;
+}
+
+
+struct GNUNET_JSON_Specification
+TALER_JSON_spec_denomination_group (const char *name,
+                                    const char *currency,
+                                    struct TALER_DenominationGroup *group)
+{
+  struct GNUNET_JSON_Specification ret = {
+    .cls = (void *) currency,
+    .parser = &parse_denomination_group,
+    .field = name,
+    .ptr = group,
+    .ptr_size = sizeof(*group)
+  };
+
+  return ret;
+}
+
+
+/**
+ * Parse given JSON object to an encrypted contract.
+ *
+ * @param cls closure, NULL
+ * @param root the json object representing data
+ * @param[out] spec where to write the data
+ * @return #GNUNET_OK upon successful parsing; #GNUNET_SYSERR upon error
+ */
+static enum GNUNET_GenericReturnValue
+parse_econtract (void *cls,
+                 json_t *root,
+                 struct GNUNET_JSON_Specification *spec)
+{
+  struct TALER_EncryptedContract *econtract = spec->ptr;
+  struct GNUNET_JSON_Specification ispec[] = {
+    GNUNET_JSON_spec_varsize ("econtract",
+                              &econtract->econtract,
+                              &econtract->econtract_size),
+    GNUNET_JSON_spec_fixed_auto ("econtract_sig",
+                                 &econtract->econtract_sig),
+    GNUNET_JSON_spec_fixed_auto ("contract_pub",
+                                 &econtract->contract_pub),
+    GNUNET_JSON_spec_end ()
+  };
+  const char *emsg;
+  unsigned int eline;
+
+  (void) cls;
+  if (GNUNET_OK !=
+      GNUNET_JSON_parse (root,
+                         ispec,
+                         &emsg,
+                         &eline))
+  {
+    GNUNET_break_op (0);
+    return GNUNET_SYSERR;
+  }
+  return GNUNET_OK;
+}
+
+
+/**
+ * Cleanup data left from parsing encrypted contract.
+ *
+ * @param cls closure, NULL
+ * @param[out] spec where to free the data
+ */
+static void
+clean_econtract (void *cls,
+                 struct GNUNET_JSON_Specification *spec)
+{
+  struct TALER_EncryptedContract *econtract = spec->ptr;
+
+  (void) cls;
+  GNUNET_free (econtract->econtract);
+}
+
+
+struct GNUNET_JSON_Specification
+TALER_JSON_spec_econtract (const char *name,
+                           struct TALER_EncryptedContract *econtract)
+{
+  struct GNUNET_JSON_Specification ret = {
+    .parser = &parse_econtract,
+    .cleaner = &clean_econtract,
+    .field = name,
+    .ptr = econtract
+  };
+
+  return ret;
+}
+
+
+/**
+ * Parse given JSON object to an age commitmnet
+ *
+ * @param cls closure, NULL
+ * @param root the json object representing data
+ * @param[out] spec where to write the data
+ * @return #GNUNET_OK upon successful parsing; #GNUNET_SYSERR upon error
+ */
+static enum GNUNET_GenericReturnValue
+parse_age_commitment (void *cls,
+                      json_t *root,
+                      struct GNUNET_JSON_Specification *spec)
+{
+  struct TALER_AgeCommitment *age_commitment = spec->ptr;
+  json_t *pk;
+  unsigned int idx;
+  size_t num;
+
+  (void) cls;
+  if ( (NULL == root) ||
+       (! json_is_array (root)))
+  {
+    GNUNET_break_op (0);
+    return GNUNET_SYSERR;
+  }
+
+  num = json_array_size (root);
+  if (32 <= num || 0 == num)
+  {
+    GNUNET_break_op (0);
+    return GNUNET_SYSERR;
+  }
+
+  age_commitment->num = num;
+  age_commitment->keys =
+    GNUNET_new_array (num,
+                      struct TALER_AgeCommitmentPublicKeyP);
+
+  json_array_foreach (root, idx, pk) {
+    const char *emsg;
+    unsigned int eline;
+    struct GNUNET_JSON_Specification pkspec[] = {
+      GNUNET_JSON_spec_fixed_auto (
+        NULL,
+        &age_commitment->keys[idx].pub),
+      GNUNET_JSON_spec_end ()
+    };
+
+    if (GNUNET_OK !=
+        GNUNET_JSON_parse (pk,
+                           pkspec,
+                           &emsg,
+                           &eline))
+    {
+      GNUNET_break_op (0);
+      GNUNET_JSON_parse_free (spec);
+      return GNUNET_SYSERR;
+    }
+  };
+
+  return GNUNET_OK;
+}
+
+
+/**
+ * Cleanup data left from parsing age commitment
+ *
+ * @param cls closure, NULL
+ * @param[out] spec where to free the data
+ */
+static void
+clean_age_commitment (void *cls,
+                      struct GNUNET_JSON_Specification *spec)
+{
+  struct TALER_AgeCommitment *age_commitment = spec->ptr;
+
+  (void) cls;
+
+  if (NULL == age_commitment ||
+      NULL == age_commitment->keys)
+    return;
+
+  age_commitment->num = 0;
+  GNUNET_free (age_commitment->keys);
+}
+
+
+struct GNUNET_JSON_Specification
+TALER_JSON_spec_age_commitment (const char *name,
+                                struct TALER_AgeCommitment *age_commitment)
+{
+  struct GNUNET_JSON_Specification ret = {
+    .parser = &parse_age_commitment,
+    .cleaner = &clean_age_commitment,
+    .field = name,
+    .ptr = age_commitment
+  };
+
+  return ret;
+}
+
+
+/**
+ * Parse given JSON object to denomination public key.
+ *
+ * @param cls closure, NULL
+ * @param root the json object representing data
+ * @param[out] spec where to write the data
+ * @return #GNUNET_OK upon successful parsing; #GNUNET_SYSERR upon error
+ */
+static enum GNUNET_GenericReturnValue
+parse_denom_pub (void *cls,
+                 json_t *root,
+                 struct GNUNET_JSON_Specification *spec)
+{
+  struct TALER_DenominationPublicKey *denom_pub = spec->ptr;
+  struct GNUNET_CRYPTO_BlindSignPublicKey *bsign_pub;
+  const char *cipher;
+  bool age_mask_missing = false;
+  struct GNUNET_JSON_Specification dspec[] = {
+    GNUNET_JSON_spec_string ("cipher",
+                             &cipher),
+    GNUNET_JSON_spec_mark_optional (
+      GNUNET_JSON_spec_uint32 ("age_mask",
+                               &denom_pub->age_mask.bits),
+      &age_mask_missing),
+    GNUNET_JSON_spec_end ()
+  };
+  const char *emsg;
+  unsigned int eline;
+
+  (void) cls;
+  if (GNUNET_OK !=
+      GNUNET_JSON_parse (root,
+                         dspec,
+                         &emsg,
+                         &eline))
+  {
+    GNUNET_break_op (0);
+    return GNUNET_SYSERR;
+  }
+
+  if (age_mask_missing)
+    denom_pub->age_mask.bits = 0;
+  bsign_pub = GNUNET_new (struct GNUNET_CRYPTO_BlindSignPublicKey);
+  bsign_pub->rc = 1;
+  bsign_pub->cipher = string_to_cipher (cipher);
+  switch (bsign_pub->cipher)
+  {
+  case GNUNET_CRYPTO_BSA_INVALID:
+    break;
+  case GNUNET_CRYPTO_BSA_RSA:
+    {
+      struct GNUNET_JSON_Specification ispec[] = {
+        GNUNET_JSON_spec_rsa_public_key (
+          "rsa_public_key",
+          &bsign_pub->details.rsa_public_key),
+        GNUNET_JSON_spec_end ()
+      };
+
+      if (GNUNET_OK !=
+          GNUNET_JSON_parse (root,
+                             ispec,
+                             &emsg,
+                             &eline))
+      {
+        GNUNET_break_op (0);
+        GNUNET_free (bsign_pub);
+        return GNUNET_SYSERR;
+      }
+      denom_pub->bsign_pub_key = bsign_pub;
+      return GNUNET_OK;
+    }
+  case GNUNET_CRYPTO_BSA_CS:
+    {
+      struct GNUNET_JSON_Specification ispec[] = {
+        GNUNET_JSON_spec_fixed ("cs_public_key",
+                                &bsign_pub->details.cs_public_key,
+                                sizeof (bsign_pub->details.cs_public_key)),
+        GNUNET_JSON_spec_end ()
+      };
+
+      if (GNUNET_OK !=
+          GNUNET_JSON_parse (root,
+                             ispec,
+                             &emsg,
+                             &eline))
+      {
+        GNUNET_break_op (0);
+        GNUNET_free (bsign_pub);
+        return GNUNET_SYSERR;
+      }
+      denom_pub->bsign_pub_key = bsign_pub;
+      return GNUNET_OK;
+    }
+  }
+  GNUNET_break_op (0);
+  GNUNET_free (bsign_pub);
+  return GNUNET_SYSERR;
+}
+
+
+/**
+ * Cleanup data left from parsing denomination public key.
+ *
+ * @param cls closure, NULL
+ * @param[out] spec where to free the data
+ */
+static void
+clean_denom_pub (void *cls,
+                 struct GNUNET_JSON_Specification *spec)
+{
+  struct TALER_DenominationPublicKey *denom_pub = spec->ptr;
+
+  (void) cls;
+  TALER_denom_pub_free (denom_pub);
+}
+
+
+struct GNUNET_JSON_Specification
+TALER_JSON_spec_denom_pub (const char *field,
+                           struct TALER_DenominationPublicKey *pk)
+{
+  struct GNUNET_JSON_Specification ret = {
+    .parser = &parse_denom_pub,
+    .cleaner = &clean_denom_pub,
+    .field = field,
+    .ptr = pk
+  };
+
+  pk->bsign_pub_key = NULL;
+  return ret;
+}
+
+
+/**
+ * Parse given JSON object partially into a denomination public key.
+ *
+ * Depending on the cipher in cls, it parses the corresponding public key type.
+ *
+ * @param cls closure, enum GNUNET_CRYPTO_BlindSignatureAlgorithm
+ * @param root the json object representing data
+ * @param[out] spec where to write the data
+ * @return #GNUNET_OK upon successful parsing; #GNUNET_SYSERR upon error
+ */
+static enum GNUNET_GenericReturnValue
+parse_denom_pub_cipher (void *cls,
+                        json_t *root,
+                        struct GNUNET_JSON_Specification *spec)
+{
+  struct TALER_DenominationPublicKey *denom_pub = spec->ptr;
+  enum GNUNET_CRYPTO_BlindSignatureAlgorithm cipher =
+    (enum GNUNET_CRYPTO_BlindSignatureAlgorithm) (long) cls;
+  struct GNUNET_CRYPTO_BlindSignPublicKey *bsign_pub;
+  const char *emsg;
+  unsigned int eline;
+
+  bsign_pub = GNUNET_new (struct GNUNET_CRYPTO_BlindSignPublicKey);
+  bsign_pub->cipher = cipher;
+  bsign_pub->rc = 1;
+  switch (cipher)
+  {
+  case GNUNET_CRYPTO_BSA_INVALID:
+    break;
+  case GNUNET_CRYPTO_BSA_RSA:
+    {
+      struct GNUNET_JSON_Specification ispec[] = {
+        GNUNET_JSON_spec_rsa_public_key (
+          "rsa_pub",
+          &bsign_pub->details.rsa_public_key),
+        GNUNET_JSON_spec_end ()
+      };
+
+      if (GNUNET_OK !=
+          GNUNET_JSON_parse (root,
+                             ispec,
+                             &emsg,
+                             &eline))
+      {
+        GNUNET_break_op (0);
+        GNUNET_free (bsign_pub);
+        return GNUNET_SYSERR;
+      }
+      denom_pub->bsign_pub_key = bsign_pub;
+      return GNUNET_OK;
+    }
+  case GNUNET_CRYPTO_BSA_CS:
+    {
+      struct GNUNET_JSON_Specification ispec[] = {
+        GNUNET_JSON_spec_fixed ("cs_pub",
+                                &bsign_pub->details.cs_public_key,
+                                sizeof (bsign_pub->details.cs_public_key)),
+        GNUNET_JSON_spec_end ()
+      };
+
+      if (GNUNET_OK !=
+          GNUNET_JSON_parse (root,
+                             ispec,
+                             &emsg,
+                             &eline))
+      {
+        GNUNET_break_op (0);
+        GNUNET_free (bsign_pub);
+        return GNUNET_SYSERR;
+      }
+      denom_pub->bsign_pub_key = bsign_pub;
+      return GNUNET_OK;
+    }
+  }
+  GNUNET_break_op (0);
+  GNUNET_free (bsign_pub);
+  return GNUNET_SYSERR;
+}
+
+
+struct GNUNET_JSON_Specification
+TALER_JSON_spec_denom_pub_cipher (const char *field,
+                                  enum GNUNET_CRYPTO_BlindSignatureAlgorithm
+                                  cipher,
+                                  struct TALER_DenominationPublicKey *pk)
+{
+  struct GNUNET_JSON_Specification ret = {
+    .parser = &parse_denom_pub_cipher,
+    .cleaner = &clean_denom_pub,
+    .field = field,
+    .cls = (void *) cipher,
+    .ptr = pk
+  };
+
+  return ret;
+}
+
+
+/**
+ * Parse given JSON object to denomination signature.
+ *
+ * @param cls closure, NULL
+ * @param root the json object representing data
+ * @param[out] spec where to write the data
+ * @return #GNUNET_OK upon successful parsing; #GNUNET_SYSERR upon error
+ */
+static enum GNUNET_GenericReturnValue
+parse_denom_sig (void *cls,
+                 json_t *root,
+                 struct GNUNET_JSON_Specification *spec)
+{
+  struct TALER_DenominationSignature *denom_sig = spec->ptr;
+  struct GNUNET_CRYPTO_UnblindedSignature *unblinded_sig;
+  const char *cipher;
+  struct GNUNET_JSON_Specification dspec[] = {
+    GNUNET_JSON_spec_string ("cipher",
+                             &cipher),
+    GNUNET_JSON_spec_end ()
+  };
+  const char *emsg;
+  unsigned int eline;
+
+  (void) cls;
+  if (GNUNET_OK !=
+      GNUNET_JSON_parse (root,
+                         dspec,
+                         &emsg,
+                         &eline))
+  {
+    GNUNET_break_op (0);
+    return GNUNET_SYSERR;
+  }
+  unblinded_sig = GNUNET_new (struct GNUNET_CRYPTO_UnblindedSignature);
+  unblinded_sig->cipher = string_to_cipher (cipher);
+  unblinded_sig->rc = 1;
+  switch (unblinded_sig->cipher)
+  {
+  case GNUNET_CRYPTO_BSA_INVALID:
+    break;
+  case GNUNET_CRYPTO_BSA_RSA:
+    {
+      struct GNUNET_JSON_Specification ispec[] = {
+        GNUNET_JSON_spec_rsa_signature (
+          "rsa_signature",
+          &unblinded_sig->details.rsa_signature),
+        GNUNET_JSON_spec_end ()
+      };
+
+      if (GNUNET_OK !=
+          GNUNET_JSON_parse (root,
+                             ispec,
+                             &emsg,
+                             &eline))
+      {
+        GNUNET_break_op (0);
+        GNUNET_free (unblinded_sig);
+        return GNUNET_SYSERR;
+      }
+      denom_sig->unblinded_sig = unblinded_sig;
+      return GNUNET_OK;
+    }
+  case GNUNET_CRYPTO_BSA_CS:
+    {
+      struct GNUNET_JSON_Specification ispec[] = {
+        GNUNET_JSON_spec_fixed_auto ("cs_signature_r",
+                                     &unblinded_sig->details.cs_signature.
+                                     r_point),
+        GNUNET_JSON_spec_fixed_auto ("cs_signature_s",
+                                     &unblinded_sig->details.cs_signature.
+                                     s_scalar),
+        GNUNET_JSON_spec_end ()
+      };
+
+      if (GNUNET_OK !=
+          GNUNET_JSON_parse (root,
+                             ispec,
+                             &emsg,
+                             &eline))
+      {
+        GNUNET_break_op (0);
+        GNUNET_free (unblinded_sig);
+        return GNUNET_SYSERR;
+      }
+      denom_sig->unblinded_sig = unblinded_sig;
+      return GNUNET_OK;
+    }
+  }
+  GNUNET_break_op (0);
+  GNUNET_free (unblinded_sig);
+  return GNUNET_SYSERR;
+}
+
+
+/**
+ * Cleanup data left from parsing denomination public key.
+ *
+ * @param cls closure, NULL
+ * @param[out] spec where to free the data
+ */
+static void
+clean_denom_sig (void *cls,
+                 struct GNUNET_JSON_Specification *spec)
+{
+  struct TALER_DenominationSignature *denom_sig = spec->ptr;
+
+  (void) cls;
+  TALER_denom_sig_free (denom_sig);
+}
+
+
+struct GNUNET_JSON_Specification
+TALER_JSON_spec_denom_sig (const char *field,
+                           struct TALER_DenominationSignature *sig)
+{
+  struct GNUNET_JSON_Specification ret = {
+    .parser = &parse_denom_sig,
+    .cleaner = &clean_denom_sig,
+    .field = field,
+    .ptr = sig
+  };
+
+  sig->unblinded_sig = NULL;
+  return ret;
+}
+
+
+/**
+ * Parse given JSON object to blinded denomination signature.
+ *
+ * @param cls closure, NULL
+ * @param root the json object representing data
+ * @param[out] spec where to write the data
+ * @return #GNUNET_OK upon successful parsing; #GNUNET_SYSERR upon error
+ */
+static enum GNUNET_GenericReturnValue
+parse_blinded_denom_sig (void *cls,
+                         json_t *root,
+                         struct GNUNET_JSON_Specification *spec)
+{
+  struct TALER_BlindedDenominationSignature *denom_sig = spec->ptr;
+  struct GNUNET_CRYPTO_BlindedSignature *blinded_sig;
+  const char *cipher;
+  struct GNUNET_JSON_Specification dspec[] = {
+    GNUNET_JSON_spec_string ("cipher",
+                             &cipher),
+    GNUNET_JSON_spec_end ()
+  };
+  const char *emsg;
+  unsigned int eline;
+
+  (void) cls;
+  if (GNUNET_OK !=
+      GNUNET_JSON_parse (root,
+                         dspec,
+                         &emsg,
+                         &eline))
+  {
+    GNUNET_break_op (0);
+    return GNUNET_SYSERR;
+  }
+  blinded_sig = GNUNET_new (struct GNUNET_CRYPTO_BlindedSignature);
+  blinded_sig->cipher = string_to_cipher (cipher);
+  blinded_sig->rc = 1;
+  switch (blinded_sig->cipher)
+  {
+  case GNUNET_CRYPTO_BSA_INVALID:
+    break;
+  case GNUNET_CRYPTO_BSA_RSA:
+    {
+      struct GNUNET_JSON_Specification ispec[] = {
+        GNUNET_JSON_spec_rsa_signature (
+          "blinded_rsa_signature",
+          &blinded_sig->details.blinded_rsa_signature),
+        GNUNET_JSON_spec_end ()
+      };
+
+      if (GNUNET_OK !=
+          GNUNET_JSON_parse (root,
+                             ispec,
+                             &emsg,
+                             &eline))
+      {
+        GNUNET_break_op (0);
+        GNUNET_free (blinded_sig);
+        return GNUNET_SYSERR;
+      }
+      denom_sig->blinded_sig = blinded_sig;
+      return GNUNET_OK;
+    }
+  case GNUNET_CRYPTO_BSA_CS:
+    {
+      struct GNUNET_JSON_Specification ispec[] = {
+        GNUNET_JSON_spec_uint32 ("b",
+                                 &blinded_sig->details.blinded_cs_answer.b),
+        GNUNET_JSON_spec_fixed_auto ("s",
+                                     &blinded_sig->details.blinded_cs_answer.
+                                     s_scalar),
+        GNUNET_JSON_spec_end ()
+      };
+
+      if (GNUNET_OK !=
+          GNUNET_JSON_parse (root,
+                             ispec,
+                             &emsg,
+                             &eline))
+      {
+        GNUNET_break_op (0);
+        GNUNET_free (blinded_sig);
+        return GNUNET_SYSERR;
+      }
+      denom_sig->blinded_sig = blinded_sig;
+      return GNUNET_OK;
+    }
+  }
+  GNUNET_break_op (0);
+  GNUNET_free (blinded_sig);
+  return GNUNET_SYSERR;
+}
+
+
+/**
+ * Cleanup data left from parsing denomination public key.
+ *
+ * @param cls closure, NULL
+ * @param[out] spec where to free the data
+ */
+static void
+clean_blinded_denom_sig (void *cls,
+                         struct GNUNET_JSON_Specification *spec)
+{
+  struct TALER_BlindedDenominationSignature *denom_sig = spec->ptr;
+
+  (void) cls;
+  TALER_blinded_denom_sig_free (denom_sig);
+}
+
+
+struct GNUNET_JSON_Specification
+TALER_JSON_spec_blinded_denom_sig (
+  const char *field,
+  struct TALER_BlindedDenominationSignature *sig)
+{
+  struct GNUNET_JSON_Specification ret = {
+    .parser = &parse_blinded_denom_sig,
+    .cleaner = &clean_blinded_denom_sig,
+    .field = field,
+    .ptr = sig
+  };
+
+  sig->blinded_sig = NULL;
+  return ret;
+}
+
+
+/**
+ * Parse given JSON object to blinded planchet.
+ *
+ * @param cls closure, NULL
+ * @param root the json object representing data
+ * @param[out] spec where to write the data
+ * @return #GNUNET_OK upon successful parsing; #GNUNET_SYSERR upon error
+ */
+static enum GNUNET_GenericReturnValue
+parse_blinded_planchet (void *cls,
+                        json_t *root,
+                        struct GNUNET_JSON_Specification *spec)
+{
+  struct TALER_BlindedPlanchet *blinded_planchet = spec->ptr;
+  struct GNUNET_CRYPTO_BlindedMessage *blinded_message;
+  const char *cipher;
+  struct GNUNET_JSON_Specification dspec[] = {
+    GNUNET_JSON_spec_string ("cipher",
+                             &cipher),
+    GNUNET_JSON_spec_end ()
+  };
+  const char *emsg;
+  unsigned int eline;
+
+  (void) cls;
+  if (GNUNET_OK !=
+      GNUNET_JSON_parse (root,
+                         dspec,
+                         &emsg,
+                         &eline))
+  {
+    GNUNET_break_op (0);
+    return GNUNET_SYSERR;
+  }
+  blinded_message = GNUNET_new (struct GNUNET_CRYPTO_BlindedMessage);
+  blinded_message->rc = 1;
+  blinded_message->cipher = string_to_cipher (cipher);
+  switch (blinded_message->cipher)
+  {
+  case GNUNET_CRYPTO_BSA_INVALID:
+    break;
+  case GNUNET_CRYPTO_BSA_RSA:
+    {
+      struct GNUNET_JSON_Specification ispec[] = {
+        GNUNET_JSON_spec_varsize (
+          "rsa_blinded_planchet",
+          &blinded_message->details.rsa_blinded_message.blinded_msg,
+          &blinded_message->details.rsa_blinded_message.blinded_msg_size),
+        GNUNET_JSON_spec_end ()
+      };
+
+      if (GNUNET_OK !=
+          GNUNET_JSON_parse (root,
+                             ispec,
+                             &emsg,
+                             &eline))
+      {
+        GNUNET_break_op (0);
+        GNUNET_free (blinded_message);
+        return GNUNET_SYSERR;
+      }
+      blinded_planchet->blinded_message = blinded_message;
+      return GNUNET_OK;
+    }
+  case GNUNET_CRYPTO_BSA_CS:
+    {
+      struct GNUNET_JSON_Specification ispec[] = {
+        GNUNET_JSON_spec_fixed_auto (
+          "cs_nonce",
+          &blinded_message->details.cs_blinded_message.nonce),
+        GNUNET_JSON_spec_fixed_auto (
+          "cs_blinded_c0",
+          &blinded_message->details.cs_blinded_message.c[0]),
+        GNUNET_JSON_spec_fixed_auto (
+          "cs_blinded_c1",
+          &blinded_message->details.cs_blinded_message.c[1]),
+        GNUNET_JSON_spec_end ()
+      };
+
+      if (GNUNET_OK !=
+          GNUNET_JSON_parse (root,
+                             ispec,
+                             &emsg,
+                             &eline))
+      {
+        GNUNET_break_op (0);
+        GNUNET_free (blinded_message);
+        return GNUNET_SYSERR;
+      }
+      blinded_planchet->blinded_message = blinded_message;
+      return GNUNET_OK;
+    }
+  }
+  GNUNET_break_op (0);
+  GNUNET_free (blinded_message);
+  return GNUNET_SYSERR;
+}
+
+
+/**
+ * Cleanup data left from parsing blinded planchet.
+ *
+ * @param cls closure, NULL
+ * @param[out] spec where to free the data
+ */
+static void
+clean_blinded_planchet (void *cls,
+                        struct GNUNET_JSON_Specification *spec)
+{
+  struct TALER_BlindedPlanchet *blinded_planchet = spec->ptr;
+
+  (void) cls;
+  TALER_blinded_planchet_free (blinded_planchet);
+}
+
+
+struct GNUNET_JSON_Specification
+TALER_JSON_spec_blinded_planchet (const char *field,
+                                  struct TALER_BlindedPlanchet 
*blinded_planchet)
+{
+  struct GNUNET_JSON_Specification ret = {
+    .parser = &parse_blinded_planchet,
+    .cleaner = &clean_blinded_planchet,
+    .field = field,
+    .ptr = blinded_planchet
+  };
+
+  blinded_planchet->blinded_message = NULL;
+  return ret;
+}
+
+
+/**
+ * Parse given JSON object to exchange withdraw values (/csr).
+ *
+ * @param cls closure, NULL
+ * @param root the json object representing data
+ * @param[out] spec where to write the data
+ * @return #GNUNET_OK upon successful parsing; #GNUNET_SYSERR upon error
+ */
+static enum GNUNET_GenericReturnValue
+parse_exchange_withdraw_values (void *cls,
+                                json_t *root,
+                                struct GNUNET_JSON_Specification *spec)
+{
+  struct TALER_ExchangeWithdrawValues *ewv = spec->ptr;
+  struct GNUNET_CRYPTO_BlindingInputValues *bi;
+  const char *cipher;
+  struct GNUNET_JSON_Specification dspec[] = {
+    GNUNET_JSON_spec_string ("cipher",
+                             &cipher),
+    GNUNET_JSON_spec_end ()
+  };
+  const char *emsg;
+  unsigned int eline;
+  enum GNUNET_CRYPTO_BlindSignatureAlgorithm ci;
+
+  (void) cls;
+  if (GNUNET_OK !=
+      GNUNET_JSON_parse (root,
+                         dspec,
+                         &emsg,
+                         &eline))
+  {
+    GNUNET_break_op (0);
+    return GNUNET_SYSERR;
+  }
+  ci = string_to_cipher (cipher);
+  switch (ci)
+  {
+  case GNUNET_CRYPTO_BSA_INVALID:
+    break;
+  case GNUNET_CRYPTO_BSA_RSA:
+    ewv->blinding_inputs = TALER_denom_ewv_rsa_singleton ()->blinding_inputs;
+    return GNUNET_OK;
+  case GNUNET_CRYPTO_BSA_CS:
+    bi = GNUNET_new (struct GNUNET_CRYPTO_BlindingInputValues);
+    bi->cipher = GNUNET_CRYPTO_BSA_CS;
+    bi->rc = 1;
+    {
+      struct GNUNET_JSON_Specification ispec[] = {
+        GNUNET_JSON_spec_fixed (
+          "r_pub_0",
+          &bi->details.cs_values.r_pub[0],
+          sizeof (struct GNUNET_CRYPTO_CsRPublic)),
+        GNUNET_JSON_spec_fixed (
+          "r_pub_1",
+          &bi->details.cs_values.r_pub[1],
+          sizeof (struct GNUNET_CRYPTO_CsRPublic)),
+        GNUNET_JSON_spec_end ()
+      };
+
+      if (GNUNET_OK !=
+          GNUNET_JSON_parse (root,
+                             ispec,
+                             &emsg,
+                             &eline))
+      {
+        GNUNET_break_op (0);
+        GNUNET_free (bi);
+        return GNUNET_SYSERR;
+      }
+      ewv->blinding_inputs = bi;
+      return GNUNET_OK;
+    }
+  }
+  GNUNET_break_op (0);
+  return GNUNET_SYSERR;
+}
+
+
+/**
+ * Cleanup data left from parsing withdraw values
+ *
+ * @param cls closure, NULL
+ * @param[out] spec where to free the data
+ */
+static void
+clean_exchange_withdraw_values (
+  void *cls,
+  struct GNUNET_JSON_Specification *spec)
+{
+  struct TALER_ExchangeWithdrawValues *ewv = spec->ptr;
+
+  (void) cls;
+  TALER_denom_ewv_free (ewv);
+}
+
+
+struct GNUNET_JSON_Specification
+TALER_JSON_spec_exchange_withdraw_values (
+  const char *field,
+  struct TALER_ExchangeWithdrawValues *ewv)
+{
+  struct GNUNET_JSON_Specification ret = {
+    .parser = &parse_exchange_withdraw_values,
+    .cleaner = &clean_exchange_withdraw_values,
+    .field = field,
+    .ptr = ewv
+  };
+
+  ewv->blinding_inputs = NULL;
+  return ret;
+}
+
+
+/**
+ * Closure for #parse_i18n_string.
+ */
+struct I18nContext
+{
+  /**
+   * Language pattern to match.
+   */
+  char *lp;
+
+  /**
+   * Name of the field to match.
+   */
+  const char *field;
+};
+
+
+/**
+ * Parse given JSON object to internationalized string.
+ *
+ * @param cls closure, our `struct I18nContext *`
+ * @param root the json object representing data
+ * @param[out] spec where to write the data
+ * @return #GNUNET_OK upon successful parsing; #GNUNET_SYSERR upon error
+ */
+static enum GNUNET_GenericReturnValue
+parse_i18n_string (void *cls,
+                   json_t *root,
+                   struct GNUNET_JSON_Specification *spec)
+{
+  struct I18nContext *ctx = cls;
+  json_t *i18n;
+  json_t *val;
+
+  {
+    char *i18nf;
+
+    GNUNET_asprintf (&i18nf,
+                     "%s_i18n",
+                     ctx->field);
+    i18n = json_object_get (root,
+                            i18nf);
+    GNUNET_free (i18nf);
+  }
+
+  val = json_object_get (root,
+                         ctx->field);
+  if ( (NULL != i18n) &&
+       (NULL != ctx->lp) )
+  {
+    double best = 0.0;
+    json_t *pos;
+    const char *lang;
+
+    json_object_foreach (i18n, lang, pos)
+    {
+      double score;
+
+      score = TALER_language_matches (ctx->lp,
+                                      lang);
+      if (score > best)
+      {
+        best = score;
+        val = pos;
+      }
+    }
+  }
+
+  {
+    const char *str;
+
+    str = json_string_value (val);
+    *(const char **) spec->ptr = str;
+  }
+  return GNUNET_OK;
+}
+
+
+/**
+ * Function called to clean up data from earlier parsing.
+ *
+ * @param cls closure
+ * @param spec our specification entry with data to clean.
+ */
+static void
+i18n_cleaner (void *cls,
+              struct GNUNET_JSON_Specification *spec)
+{
+  struct I18nContext *ctx = cls;
+
+  (void) spec;
+  if (NULL != ctx)
+  {
+    GNUNET_free (ctx->lp);
+    GNUNET_free (ctx);
+  }
+}
+
+
+struct GNUNET_JSON_Specification
+TALER_JSON_spec_i18n_string (const char *name,
+                             const char *language_pattern,
+                             const char **strptr)
+{
+  struct I18nContext *ctx = GNUNET_new (struct I18nContext);
+  struct GNUNET_JSON_Specification ret = {
+    .parser = &parse_i18n_string,
+    .cleaner = &i18n_cleaner,
+    .cls = ctx,
+    .field = NULL, /* we want the main object */
+    .ptr = strptr,
+    .ptr_size = 0,
+    .size_ptr = NULL
+  };
+
+  ctx->lp = (NULL != language_pattern)
+    ? GNUNET_strdup (language_pattern)
+    : NULL;
+  ctx->field = name;
+  *strptr = NULL;
+  return ret;
+}
+
+
+struct GNUNET_JSON_Specification
+TALER_JSON_spec_i18n_str (const char *name,
+                          const char **strptr)
+{
+  const char *lang = getenv ("LANG");
+  char *dot;
+  char *l;
+  struct GNUNET_JSON_Specification ret;
+
+  if (NULL != lang)
+  {
+    dot = strchr (lang,
+                  '.');
+    if (NULL == dot)
+      l = GNUNET_strdup (lang);
+    else
+      l = GNUNET_strndup (lang,
+                          dot - lang);
+  }
+  else
+  {
+    l = NULL;
+  }
+  ret = TALER_JSON_spec_i18n_string (name,
+                                     l,
+                                     strptr);
+  GNUNET_free (l);
+  return ret;
+}
+
+
+/**
+ * Parse given JSON object with Taler error code.
+ *
+ * @param cls closure, NULL
+ * @param root the json object representing data
+ * @param[out] spec where to write the data
+ * @return #GNUNET_OK upon successful parsing; #GNUNET_SYSERR upon error
+ */
+static enum GNUNET_GenericReturnValue
+parse_ec (void *cls,
+          json_t *root,
+          struct GNUNET_JSON_Specification *spec)
+{
+  enum TALER_ErrorCode *ec = spec->ptr;
+  json_int_t num;
+
+  (void) cls;
+  if (! json_is_integer (root))
+  {
+    GNUNET_break_op (0);
+    return GNUNET_SYSERR;
+  }
+  num = json_integer_value (root);
+  if (num < 0)
+  {
+    GNUNET_break_op (0);
+    *ec = TALER_EC_INVALID;
+    return GNUNET_SYSERR;
+  }
+  *ec = (enum TALER_ErrorCode) num;
+  return GNUNET_OK;
+}
+
+
+struct GNUNET_JSON_Specification
+TALER_JSON_spec_ec (const char *field,
+                    enum TALER_ErrorCode *ec)
+{
+  struct GNUNET_JSON_Specification ret = {
+    .parser = &parse_ec,
+    .field = field,
+    .ptr = ec
+  };
+
+  *ec = TALER_EC_NONE;
+  return ret;
+}
+
+
+/**
+ * Parse given JSON object to web URL.
+ *
+ * @param cls closure, NULL
+ * @param root the json object representing data
+ * @param[out] spec where to write the data
+ * @return #GNUNET_OK upon successful parsing; #GNUNET_SYSERR upon error
+ */
+static enum GNUNET_GenericReturnValue
+parse_web_url (void *cls,
+               json_t *root,
+               struct GNUNET_JSON_Specification *spec)
+{
+  const char *str;
+
+  (void) cls;
+  str = json_string_value (root);
+  if (NULL == str)
+  {
+    GNUNET_break_op (0);
+    return GNUNET_SYSERR;
+  }
+  if (! TALER_is_web_url (str))
+  {
+    GNUNET_break_op (0);
+    return GNUNET_SYSERR;
+  }
+  *(const char **) spec->ptr = str;
+  return GNUNET_OK;
+}
+
+
+struct GNUNET_JSON_Specification
+TALER_JSON_spec_web_url (const char *field,
+                         const char **url)
+{
+  struct GNUNET_JSON_Specification ret = {
+    .parser = &parse_web_url,
+    .field = field,
+    .ptr = url
+  };
+
+  *url = NULL;
+  return ret;
+}
+
+
+/**
+ * Parse given JSON object to payto:// URI.
+ *
+ * @param cls closure, NULL
+ * @param root the json object representing data
+ * @param[out] spec where to write the data
+ * @return #GNUNET_OK upon successful parsing; #GNUNET_SYSERR upon error
+ */
+static enum GNUNET_GenericReturnValue
+parse_payto_uri (void *cls,
+                 json_t *root,
+                 struct GNUNET_JSON_Specification *spec)
+{
+  const char *str;
+  char *err;
+
+  (void) cls;
+  str = json_string_value (root);
+  if (NULL == str)
+  {
+    GNUNET_break_op (0);
+    return GNUNET_SYSERR;
+  }
+  err = TALER_payto_validate (str);
+  if (NULL != err)
+  {
+    GNUNET_break_op (0);
+    GNUNET_free (err);
+    return GNUNET_SYSERR;
+  }
+  *(const char **) spec->ptr = str;
+  return GNUNET_OK;
+}
+
+
+struct GNUNET_JSON_Specification
+TALER_JSON_spec_payto_uri (const char *field,
+                           const char **payto_uri)
+{
+  struct GNUNET_JSON_Specification ret = {
+    .parser = &parse_payto_uri,
+    .field = field,
+    .ptr = payto_uri
+  };
+
+  *payto_uri = NULL;
+  return ret;
+}
+
+
+/**
+ * Parse given JSON object with protocol version.
+ *
+ * @param cls closure, NULL
+ * @param root the json object representing data
+ * @param[out] spec where to write the data
+ * @return #GNUNET_OK upon successful parsing; #GNUNET_SYSERR upon error
+ */
+static enum GNUNET_GenericReturnValue
+parse_protocol_version (void *cls,
+                        json_t *root,
+                        struct GNUNET_JSON_Specification *spec)
+{
+  struct TALER_JSON_ProtocolVersion *pv = spec->ptr;
+  const char *ver;
+  char dummy;
+
+  (void) cls;
+  if (! json_is_string (root))
+  {
+    GNUNET_break_op (0);
+    return GNUNET_SYSERR;
+  }
+  ver = json_string_value (root);
+  if (3 != sscanf (ver,
+                   "%u:%u:%u%c",
+                   &pv->current,
+                   &pv->revision,
+                   &pv->age,
+                   &dummy))
+  {
+    GNUNET_break_op (0);
+    return GNUNET_SYSERR;
+  }
+  return GNUNET_OK;
+}
+
+
+struct GNUNET_JSON_Specification
+TALER_JSON_spec_version (const char *field,
+                         struct TALER_JSON_ProtocolVersion *ver)
+{
+  struct GNUNET_JSON_Specification ret = {
+    .parser = &parse_protocol_version,
+    .field = field,
+    .ptr = ver
+  };
+
+  return ret;
+}
+
+
+/* end of json/json_helper.c */
diff --git a/src/json/json_pack.c b/src/json/json_pack.c
new file mode 100644
index 0000000..4357f9f
--- /dev/null
+++ b/src/json/json_pack.c
@@ -0,0 +1,324 @@
+/*
+  This file is part of TALER
+  Copyright (C) 2024 Taler Systems SA
+
+  TALER is free software; you can redistribute it and/or modify it under the
+  terms of the GNU General Public License as published by the Free Software
+  Foundation; either version 3, or (at your option) any later version.
+
+  TALER is distributed in the hope that it will be useful, but WITHOUT ANY
+  WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+  A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
+
+  You should have received a copy of the GNU General Public License along with
+  TALER; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>
+*/
+/**
+ * @file json/json_pack.c
+ * @brief helper functions for JSON object packing
+ * @author Christian Grothoff
+ */
+#include "taler/platform.h"
+#include <gnunet/gnunet_util_lib.h>
+#include "taler/taler_util.h"
+#include "taler/taler_json_lib.h"
+
+
+struct GNUNET_JSON_PackSpec
+TALER_JSON_pack_time_abs_human (const char *name,
+                                struct GNUNET_TIME_Absolute at)
+{
+  struct GNUNET_JSON_PackSpec ps = {
+    .field_name = name,
+    .object = json_string (
+      GNUNET_STRINGS_absolute_time_to_string (at))
+  };
+
+  return ps;
+}
+
+
+struct GNUNET_JSON_PackSpec
+TALER_JSON_pack_econtract (
+  const char *name,
+  const struct TALER_EncryptedContract *econtract)
+{
+  struct GNUNET_JSON_PackSpec ps = {
+    .field_name = name,
+  };
+
+  if (NULL == econtract)
+    return ps;
+  ps.object
+    = GNUNET_JSON_PACK (
+        GNUNET_JSON_pack_data_varsize ("econtract",
+                                       econtract->econtract,
+                                       econtract->econtract_size),
+        GNUNET_JSON_pack_data_auto ("econtract_sig",
+                                    &econtract->econtract_sig),
+        GNUNET_JSON_pack_data_auto ("contract_pub",
+                                    &econtract->contract_pub));
+  return ps;
+}
+
+
+struct GNUNET_JSON_PackSpec
+TALER_JSON_pack_age_commitment (
+  const char *name,
+  const struct TALER_AgeCommitment *age_commitment)
+{
+  struct GNUNET_JSON_PackSpec ps = {
+    .field_name = name,
+  };
+  json_t *keys;
+
+  if (NULL == age_commitment ||
+      0 == age_commitment->num)
+    return ps;
+
+  GNUNET_assert (NULL !=
+                 (keys = json_array ()));
+
+  for (size_t i = 0;
+       i < age_commitment->num;
+       i++)
+  {
+    json_t *val;
+    val = GNUNET_JSON_from_data (&age_commitment->keys[i],
+                                 sizeof(age_commitment->keys[i]));
+    GNUNET_assert (NULL != val);
+    GNUNET_assert (0 ==
+                   json_array_append_new (keys, val));
+  }
+
+  ps.object = keys;
+  return ps;
+}
+
+
+struct GNUNET_JSON_PackSpec
+TALER_JSON_pack_denom_pub (
+  const char *name,
+  const struct TALER_DenominationPublicKey *pk)
+{
+  const struct GNUNET_CRYPTO_BlindSignPublicKey *bsp;
+  struct GNUNET_JSON_PackSpec ps = {
+    .field_name = name,
+  };
+
+  if (NULL == pk)
+    return ps;
+  bsp = pk->bsign_pub_key;
+  switch (bsp->cipher)
+  {
+  case GNUNET_CRYPTO_BSA_INVALID:
+    break;
+  case GNUNET_CRYPTO_BSA_RSA:
+    ps.object
+      = GNUNET_JSON_PACK (
+          GNUNET_JSON_pack_string ("cipher",
+                                   "RSA"),
+          GNUNET_JSON_pack_uint64 ("age_mask",
+                                   pk->age_mask.bits),
+          GNUNET_JSON_pack_rsa_public_key ("rsa_public_key",
+                                           bsp->details.rsa_public_key));
+    return ps;
+  case GNUNET_CRYPTO_BSA_CS:
+    ps.object
+      = GNUNET_JSON_PACK (
+          GNUNET_JSON_pack_string ("cipher",
+                                   "CS"),
+          GNUNET_JSON_pack_uint64 ("age_mask",
+                                   pk->age_mask.bits),
+          GNUNET_JSON_pack_data_varsize ("cs_public_key",
+                                         &bsp->details.cs_public_key,
+                                         sizeof (bsp->details.cs_public_key)));
+    return ps;
+  }
+  GNUNET_assert (0);
+  return ps;
+}
+
+
+struct GNUNET_JSON_PackSpec
+TALER_JSON_pack_denom_sig (
+  const char *name,
+  const struct TALER_DenominationSignature *sig)
+{
+  const struct GNUNET_CRYPTO_UnblindedSignature *bs;
+  struct GNUNET_JSON_PackSpec ps = {
+    .field_name = name,
+  };
+
+  if (NULL == sig)
+    return ps;
+  bs = sig->unblinded_sig;
+  switch (bs->cipher)
+  {
+  case GNUNET_CRYPTO_BSA_INVALID:
+    break;
+  case GNUNET_CRYPTO_BSA_RSA:
+    ps.object = GNUNET_JSON_PACK (
+      GNUNET_JSON_pack_string ("cipher",
+                               "RSA"),
+      GNUNET_JSON_pack_rsa_signature ("rsa_signature",
+                                      bs->details.rsa_signature));
+    return ps;
+  case GNUNET_CRYPTO_BSA_CS:
+    ps.object = GNUNET_JSON_PACK (
+      GNUNET_JSON_pack_string ("cipher",
+                               "CS"),
+      GNUNET_JSON_pack_data_auto ("cs_signature_r",
+                                  &bs->details.cs_signature.r_point),
+      GNUNET_JSON_pack_data_auto ("cs_signature_s",
+                                  &bs->details.cs_signature.s_scalar));
+    return ps;
+  }
+  GNUNET_assert (0);
+  return ps;
+}
+
+
+struct GNUNET_JSON_PackSpec
+TALER_JSON_pack_exchange_withdraw_values (
+  const char *name,
+  const struct TALER_ExchangeWithdrawValues *ewv)
+{
+  const struct GNUNET_CRYPTO_BlindingInputValues *biv;
+  struct GNUNET_JSON_PackSpec ps = {
+    .field_name = name,
+  };
+
+  if (NULL == ewv)
+    return ps;
+  biv = ewv->blinding_inputs;
+  switch (biv->cipher)
+  {
+  case GNUNET_CRYPTO_BSA_INVALID:
+    break;
+  case GNUNET_CRYPTO_BSA_RSA:
+    ps.object = GNUNET_JSON_PACK (
+      GNUNET_JSON_pack_string ("cipher",
+                               "RSA"));
+    return ps;
+  case GNUNET_CRYPTO_BSA_CS:
+    ps.object = GNUNET_JSON_PACK (
+      GNUNET_JSON_pack_string ("cipher",
+                               "CS"),
+      GNUNET_JSON_pack_data_varsize (
+        "r_pub_0",
+        &biv->details.cs_values.r_pub[0],
+        sizeof(struct GNUNET_CRYPTO_CsRPublic)),
+      GNUNET_JSON_pack_data_varsize (
+        "r_pub_1",
+        &biv->details.cs_values.r_pub[1],
+        sizeof(struct GNUNET_CRYPTO_CsRPublic))
+      );
+    return ps;
+  }
+  GNUNET_assert (0);
+  return ps;
+}
+
+
+struct GNUNET_JSON_PackSpec
+TALER_JSON_pack_blinded_denom_sig (
+  const char *name,
+  const struct TALER_BlindedDenominationSignature *sig)
+{
+  const struct GNUNET_CRYPTO_BlindedSignature *bs;
+  struct GNUNET_JSON_PackSpec ps = {
+    .field_name = name,
+  };
+
+  if (NULL == sig)
+    return ps;
+  bs = sig->blinded_sig;
+  switch (bs->cipher)
+  {
+  case GNUNET_CRYPTO_BSA_INVALID:
+    break;
+  case GNUNET_CRYPTO_BSA_RSA:
+    ps.object = GNUNET_JSON_PACK (
+      GNUNET_JSON_pack_string ("cipher",
+                               "RSA"),
+      GNUNET_JSON_pack_rsa_signature ("blinded_rsa_signature",
+                                      bs->details.blinded_rsa_signature));
+    return ps;
+  case GNUNET_CRYPTO_BSA_CS:
+    ps.object = GNUNET_JSON_PACK (
+      GNUNET_JSON_pack_string ("cipher",
+                               "CS"),
+      GNUNET_JSON_pack_uint64 ("b",
+                               bs->details.blinded_cs_answer.b),
+      GNUNET_JSON_pack_data_auto ("s",
+                                  &bs->details.blinded_cs_answer.s_scalar));
+    return ps;
+  }
+  GNUNET_assert (0);
+  return ps;
+}
+
+
+struct GNUNET_JSON_PackSpec
+TALER_JSON_pack_blinded_planchet (
+  const char *name,
+  const struct TALER_BlindedPlanchet *blinded_planchet)
+{
+  const struct GNUNET_CRYPTO_BlindedMessage *bm;
+  struct GNUNET_JSON_PackSpec ps = {
+    .field_name = name,
+  };
+
+  if (NULL == blinded_planchet)
+    return ps;
+  bm = blinded_planchet->blinded_message;
+  switch (bm->cipher)
+  {
+  case GNUNET_CRYPTO_BSA_INVALID:
+    break;
+  case GNUNET_CRYPTO_BSA_RSA:
+    ps.object = GNUNET_JSON_PACK (
+      GNUNET_JSON_pack_string ("cipher",
+                               "RSA"),
+      GNUNET_JSON_pack_data_varsize (
+        "rsa_blinded_planchet",
+        bm->details.rsa_blinded_message.blinded_msg,
+        bm->details.rsa_blinded_message.blinded_msg_size));
+    return ps;
+  case GNUNET_CRYPTO_BSA_CS:
+    ps.object = GNUNET_JSON_PACK (
+      GNUNET_JSON_pack_string ("cipher",
+                               "CS"),
+      GNUNET_JSON_pack_data_auto (
+        "cs_nonce",
+        &bm->details.cs_blinded_message.nonce),
+      GNUNET_JSON_pack_data_auto (
+        "cs_blinded_c0",
+        &bm->details.cs_blinded_message.c[0]),
+      GNUNET_JSON_pack_data_auto (
+        "cs_blinded_c1",
+        &bm->details.cs_blinded_message.c[1]));
+    return ps;
+  }
+  GNUNET_assert (0);
+  return ps;
+}
+
+
+struct GNUNET_JSON_PackSpec
+TALER_JSON_pack_amount (const char *name,
+                        const struct TALER_Amount *amount)
+{
+  struct GNUNET_JSON_PackSpec ps = {
+    .field_name = name,
+    .object = (NULL != amount)
+              ? TALER_JSON_from_amount (amount)
+              : NULL
+  };
+
+  return ps;
+}
+
+
+/* End of json/json_pack.c */

-- 
To stop receiving notification emails like this one, please contact
gnunet@gnunet.org.



reply via email to

[Prev in Thread] Current Thread [Next in Thread]