aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--doc/paper/taler.tex121
-rw-r--r--src/mintdb/test_mintdb.c138
2 files changed, 170 insertions, 89 deletions
diff --git a/doc/paper/taler.tex b/doc/paper/taler.tex
index a728471c0..e3fb83592 100644
--- a/doc/paper/taler.tex
+++ b/doc/paper/taler.tex
@@ -191,18 +191,20 @@ his message to the merchant.
\begin{figure}[h]
\centering
\begin{tikzpicture}
+ \tikzstyle{def} = [node distance= 5em and 7em, inner sep=1em, outer sep=.3em];
+ \node (origin) at (0,0) {};
+ \node (mint) [def,above=of origin,draw]{Mint};
+ \node (customer) [def, draw, below left=of origin] {Customer};
+ \node (merchant) [def, draw, below right=of origin] {Merchant};
+ \node (auditor) [def, draw, above right=of origin]{Auditor};
+ \tikzstyle{C} = [color=black, line width=1pt]
-\tikzstyle{def} = [node distance= 7em and 10em, inner sep=1em, outer sep=.3em];
-\node (origin) at (0,0) {};
-\node (mint) [def,above=of origin,draw]{Mint};
-\node (customer) [def, draw, below left=of origin] {Customer};
-\node (merchant) [def, draw, below right=of origin] {Merchant};
+ \draw [<-, C] (customer) -- (mint) node [midway, above, sloped] (TextNode) {withdraw coins};
+ \draw [<-, C] (mint) -- (merchant) node [midway, above, sloped] (TextNode) {deposit coins};
+ \draw [<-, C] (merchant) -- (customer) node [midway, above, sloped] (TextNode) {spend coins};
+ \draw [<-, C] (mint) -- (auditor) node [midway, above, sloped] (TextNode) {verify};
-\tikzstyle{C} = [color=black, line width=1pt]
-\draw [<-, C] (customer) -- (mint) node [midway, above, sloped] (TextNode) {withdraw coins};
-\draw [<-, C] (mint) -- (merchant) node [midway, above, sloped] (TextNode) {deposit coins};
-\draw [<-, C] (merchant) -- (customer) node [midway, above, sloped] (TextNode) {spend coins};
\end{tikzpicture}
\caption{Taler's system model for the payment system is based on Chaum~\cite{chaum1983blind}.}
\label{fig:cmm}
@@ -777,13 +779,78 @@ and $G$ is the generator of the elliptic curve.
\subsection{Linking}
-% FIXME: explain better...
-For a coin that was successfully refreshed, the mint responds to
-a request $S_{C'}(\mathtt{link})$ with $(T^{(\gamma)}_p$, $E_{\gamma}, \widetilde{C})$.
+For a coin that was successfully refreshed, the mint responds to a
+request $S_{C'}(\mathtt{link})$ with $(T^{(\gamma)}_p$, $E_{\gamma},
+\widetilde{C})$.
This allows the owner of the old coin to also obtain the private key
of the new coin, even if the refreshing protocol was illicitly
-executed by another party who learned $C'_s$ from the old owner.
+executed by another party who learned $C'_s$ from the old owner. As a
+result, linking ensures that access to the new coins minted by the
+refresh protocol is always {\em shared} with the owner of the melted
+coins. This makes it impossible to abuse the refresh protocol for
+{\em transactions}.
+
+The linking request is not expected to be used at all during ordinary
+operation of Taler. If the refresh protocol is used by Alice to
+obtain change as designed, she already knows all of the information
+and thus has little reason to request it via the linking protocol.
+The fundamental reason why the mint must provide the link protocol is
+simply to provide a threat: if Bob were to use the refresh protocol
+for a transaction of funds from Alice to him, Alice may use a link
+request to gain shared access to Bob's coins. Thus, this threat
+prevents Bob from abusing the refresh protocol to evade taxation on
+transactions.
+
+The auditor can anonymously check if the mint correctly implements the
+link request, thus preventing the mint operator from legally disabling
+this protocol component. Without the link operation, Taler would
+devolve into a payment system where both sides can be anonymous, and
+thus no longer provide taxability.
+
+
+\subsection{Error handling}
+
+During operation, there are three main types of errors that are
+expected. First, in the case of faulty clients, the responding server
+will generate an error message with detailed cryptographic proofs
+demonstrating that the client was faulty, for example by providing
+proof of double-spending or providing the previous commit and the
+location of the missmatch in the case of the reveal step in the
+refresh protocol. It is also possible that the server may claim that
+the client has been violating the protocol. In these cases, the
+clients should verify any proofs provided and if they are acceptable,
+notify the user that they are somehow ``faulty''. Similar, if the
+server indicates that the client is violating the protocol, the
+client should record the interaction and enable the user to file a
+bug report with the developer.
+
+The second case is a faulty mint service provider. Such faults will
+be detected because of protocol violations (for example, by providing
+a faulty proof or no proof). In this case, the client is expected to
+notify the auditor, providing a transcript of the interaction. The
+auditor can then (anonymously) replay the transaction, and either
+provide the (now) correct response to the client or take appropriate
+legal action against the faulty provider.
+
+The third case are transient failures, such as network failures or
+temporary hardware failures at the mint service provider. Here, the
+client may receive an explicit protocol indication (such as an HTTP
+response code 500 ``internal server error'') or simply no response.
+The appropriate behavior for the client is to automatically retry
+(after 1s, twice more at randomized times within 1 minute). If those
+three attempts fail, the user should be informed about the delay. The
+client should then retry another three times within the next 24h, and
+after that time the auditor be informed about the outage.
+
+Using this process, short term failures should be effectively obscured
+from the user, while malicious behavior is reported to the auditor who
+can then presumably rectify the situation, for example by shutting
+down the operator (while providing an opportunity for customers to
+receive refunds for the coins in circulation). To ensure that such
+refunds are possible, the operator is expected to always provide
+adequate securities for the amount of coins in circulation as part of
+the certification process.
\subsection{Refunds}
@@ -849,15 +916,15 @@ transfer.
%suitable for money laundering, we are optimistic that states will find
%the design desirable.
-We did not yet perform performance measurements for the various
-operations. However, we are pretty sure that the computational and
-bandwidth cost for transactions described in this paper is likely
-small compared to other business costs for the mint. We expect costs
-within the system to be dominated by the (replicated, transactional)
-database. However, these expenses are again likely small in relation
-to the business cost of currency transfers using traditional banking.
-Here, mint operators should be able to reduce their expenses by
-aggregating multiple transfers to the same merchant.
+We performed some initial performance measurements for the various
+operations. The main conclusion was that the computational and
+bandwidth cost for transactions described in this paper is smaller
+than $10^{-3}$ cent/transaction, and thus dwarfed by the other
+business costs for the mint. However, this figure excludes the cost
+of currency transfers using traditional banking, which a mint operator
+would ultimately have to interact with. Here, mint operators should
+be able to reduce their expenses by aggregating multiple transfers to
+the same merchant.
\section{Conclusion}
@@ -871,6 +938,15 @@ protocol may finally enable modern society to upgrade to proper
electronic wallets with efficient, secure and privacy-preserving
transactions.
+\subsection*{Acknowledgements}
+
+This work was supported by a grant from the Renewable Freedom Foundation.
+% FIXME: ARED?
+We thank Tanja Lange and Dan Bernstein for feedback on an earlier
+version of this paper, Nicolas Fournier for implementing and running
+some performance benchmarks, and Richard Stallman, Hellekin Wolf,
+Jacob Appelbaum for productive discussions and support.
+
\bibliographystyle{alpha}
\bibliography{taler}
@@ -888,6 +964,7 @@ we expect that transactions with amounts below Taler's transaction
costs to be economically meaningless. Nevertheless, we document
various ways how this could be achieved.
+
\subsection{Incremental spending}
For services that include pay-as-you-go billing, customers can over
diff --git a/src/mintdb/test_mintdb.c b/src/mintdb/test_mintdb.c
index c5c4a1f26..5b9d1c2ec 100644
--- a/src/mintdb/test_mintdb.c
+++ b/src/mintdb/test_mintdb.c
@@ -186,21 +186,74 @@ free_refresh_commit_coins_array(struct TALER_MINTDB_RefreshCommitCoin
GNUNET_free (commit_coins);
}
+#define MELT_NEW_COINS 5
+
static int
-cmp_commit_coin_arrays (struct TALER_MINTDB_RefreshCommitCoin *a,
- struct TALER_MINTDB_RefreshCommitCoin *b,
- unsigned int size)
+test_refresh_commit_coins (struct TALER_MINTDB_Session *session,
+ struct TALER_MINTDB_RefreshSession *refresh_session,
+ const struct GNUNET_HashCode *session_hash)
{
- unsigned int cnt;
+ struct TALER_MINTDB_RefreshCommitCoin *commit_coins;
+ struct TALER_MINTDB_RefreshCommitCoin *ret_commit_coins;
struct TALER_MINTDB_RefreshCommitCoin *a_ccoin;
struct TALER_RefreshLinkEncrypted *a_rlink;
struct TALER_MINTDB_RefreshCommitCoin *b_ccoin;
struct TALER_RefreshLinkEncrypted *b_rlink;
+ size_t size;
+ unsigned int cnt;
+ uint16_t cnc_index;
+ int ret;
- for (cnt = 0; cnt < size; cnt++)
+ #define COIN_ENC_MAX_SIZE 512
+ ret = GNUNET_SYSERR;
+ ret_commit_coins = NULL;
+ commit_coins = GNUNET_new_array (MELT_NEW_COINS,
+ struct TALER_MINTDB_RefreshCommitCoin);
+ cnc_index = (uint16_t) GNUNET_CRYPTO_random_u32
+ (GNUNET_CRYPTO_QUALITY_WEAK, GNUNET_MIN (MELT_NEW_COINS, UINT16_MAX));
+ for (cnt=0; cnt < MELT_NEW_COINS; cnt++)
{
- a_ccoin = &a[cnt];
- b_ccoin = &b[cnt];
+ struct TALER_MINTDB_RefreshCommitCoin *ccoin;
+ struct TALER_RefreshLinkEncrypted *rlink;
+ ccoin = &commit_coins[cnt];
+ size = GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK,
+ COIN_ENC_MAX_SIZE);
+ rlink = GNUNET_malloc (sizeof (struct TALER_RefreshLinkEncrypted) + size);
+ ccoin->refresh_link = rlink;
+ ccoin->coin_ev_size = GNUNET_CRYPTO_random_u64
+ (GNUNET_CRYPTO_QUALITY_WEAK, COIN_ENC_MAX_SIZE);
+ ccoin->coin_ev = GNUNET_malloc (ccoin->coin_ev_size);
+ GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_WEAK,
+ ccoin->coin_ev,
+ ccoin->coin_ev_size);
+ rlink->blinding_key_enc_size = size;
+ RND_BLK (&rlink->coin_priv_enc);
+ rlink->blinding_key_enc = (const char *) &rlink[1];
+ GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_WEAK,
+ (void *)rlink->blinding_key_enc,
+ rlink->blinding_key_enc_size);
+ }
+ FAILIF (GNUNET_OK !=
+ plugin->insert_refresh_commit_coins (plugin->cls,
+ session,
+ session_hash,
+ cnc_index,
+ MELT_NEW_COINS,
+ commit_coins));
+ ret_commit_coins = GNUNET_new_array (MELT_NEW_COINS,
+ struct TALER_MINTDB_RefreshCommitCoin);
+ FAILIF (GNUNET_OK !=
+ plugin->get_refresh_commit_coins (plugin->cls,
+ session,
+ session_hash,
+ cnc_index,
+ MELT_NEW_COINS,
+ ret_commit_coins));
+ /* compare the refresh commit coin arrays */
+ for (cnt = 0; cnt < MELT_NEW_COINS; cnt++)
+ {
+ a_ccoin = &commit_coins[cnt];
+ b_ccoin = &ret_commit_coins[cnt];
FAILIF (a_ccoin->coin_ev_size != b_ccoin->coin_ev_size);
FAILIF (0 != memcmp (a_ccoin->coin_ev,
a_ccoin->coin_ev,
@@ -215,9 +268,14 @@ cmp_commit_coin_arrays (struct TALER_MINTDB_RefreshCommitCoin *a,
b_rlink->coin_priv_enc,
sizeof (a_rlink->coin_priv_enc)));
}
- return GNUNET_OK;
+ ret = GNUNET_OK;
+
drop:
- return GNUNET_SYSERR;
+ if (NULL != ret_commit_coins)
+ free_refresh_commit_coins_array (ret_commit_coins, MELT_NEW_COINS);
+ if (NULL != commit_coins)
+ free_refresh_commit_coins_array (commit_coins, MELT_NEW_COINS);
+ return ret;
}
/**
@@ -231,8 +289,6 @@ static int
test_melting (struct TALER_MINTDB_Session *session)
{
#define MELT_OLD_COINS 10
-#define MELT_NEW_COINS 5
-
struct TALER_MINTDB_RefreshSession refresh_session;
struct TALER_MINTDB_RefreshSession ret_refresh_session;
struct GNUNET_HashCode session_hash;
@@ -242,10 +298,6 @@ test_melting (struct TALER_MINTDB_Session *session)
struct TALER_MINTDB_RefreshMelt *melts;
struct TALER_DenominationPublicKey *new_denom_pubs;
struct TALER_DenominationPublicKey *ret_denom_pubs;
- struct TALER_MINTDB_RefreshCommitCoin *commit_coins;
- struct TALER_MINTDB_RefreshCommitCoin *ret_commit_coins;
- size_t size;
- uint16_t cnc_index;
unsigned int cnt;
int ret;
@@ -255,8 +307,6 @@ test_melting (struct TALER_MINTDB_Session *session)
melts = NULL;
new_dkp = NULL;
new_denom_pubs = NULL;
- commit_coins = NULL;
- ret_commit_coins = NULL;
/* create and test a refresh session */
refresh_session.num_oldcoins = MELT_OLD_COINS;
refresh_session.num_newcoins = 1;
@@ -358,61 +408,15 @@ test_melting (struct TALER_MINTDB_Session *session)
(ret_denom_pubs[cnt].rsa_public_key,
new_denom_pubs[cnt].rsa_public_key));
}
-#define COIN_ENC_MAX_SIZE 512
- commit_coins = GNUNET_new_array (MELT_NEW_COINS,
- struct TALER_MINTDB_RefreshCommitCoin);
- cnc_index = (uint16_t) GNUNET_CRYPTO_random_u32
- (GNUNET_CRYPTO_QUALITY_WEAK, GNUNET_MIN (MELT_NEW_COINS, UINT16_MAX));
- for (cnt=0; cnt < MELT_NEW_COINS; cnt++)
- {
- struct TALER_MINTDB_RefreshCommitCoin *ccoin;
- struct TALER_RefreshLinkEncrypted *rlink;
- ccoin = &commit_coins[cnt];
- size = GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK,
- COIN_ENC_MAX_SIZE);
- rlink = GNUNET_malloc (sizeof (struct TALER_RefreshLinkEncrypted) + size);
- ccoin->refresh_link = rlink;
- ccoin->coin_ev_size = GNUNET_CRYPTO_random_u64
- (GNUNET_CRYPTO_QUALITY_WEAK, COIN_ENC_MAX_SIZE);
- ccoin->coin_ev = GNUNET_malloc (ccoin->coin_ev_size);
- GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_WEAK,
- ccoin->coin_ev,
- ccoin->coin_ev_size);
- rlink->blinding_key_enc_size = size;
- RND_BLK (&rlink->coin_priv_enc);
- rlink->blinding_key_enc = (const char *) &rlink[1];
- GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_WEAK,
- (void *)rlink->blinding_key_enc,
- rlink->blinding_key_enc_size);
- }
- FAILIF (GNUNET_OK !=
- plugin->insert_refresh_commit_coins (plugin->cls,
- session,
- &session_hash,
- cnc_index,
- MELT_NEW_COINS,
- commit_coins));
- ret_commit_coins = GNUNET_new_array (MELT_NEW_COINS,
- struct TALER_MINTDB_RefreshCommitCoin);
- FAILIF (GNUNET_OK !=
- plugin->get_refresh_commit_coins (plugin->cls,
- session,
- &session_hash,
- cnc_index,
- MELT_NEW_COINS,
- ret_commit_coins));
FAILIF (GNUNET_OK !=
- cmp_commit_coin_arrays (commit_coins,
- ret_commit_coins,
- MELT_NEW_COINS));
+ test_refresh_commit_coins (session,
+ &refresh_session,
+ &session_hash));
+
ret = GNUNET_OK;
drop:
destroy_denom_key_pair (dkp);
- if (NULL != ret_commit_coins)
- free_refresh_commit_coins_array (ret_commit_coins, MELT_NEW_COINS);
- if (NULL != commit_coins)
- free_refresh_commit_coins_array (commit_coins, MELT_NEW_COINS);
if (NULL != melts)
{
for (cnt = 0; cnt < MELT_OLD_COINS; cnt++)