edits
This commit is contained in:
commit
7237665713
@ -191,18 +191,20 @@ his message to the merchant.
|
|||||||
\begin{figure}[h]
|
\begin{figure}[h]
|
||||||
\centering
|
\centering
|
||||||
\begin{tikzpicture}
|
\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];
|
\draw [<-, C] (customer) -- (mint) node [midway, above, sloped] (TextNode) {withdraw coins};
|
||||||
\node (origin) at (0,0) {};
|
\draw [<-, C] (mint) -- (merchant) node [midway, above, sloped] (TextNode) {deposit coins};
|
||||||
\node (mint) [def,above=of origin,draw]{Mint};
|
\draw [<-, C] (merchant) -- (customer) node [midway, above, sloped] (TextNode) {spend coins};
|
||||||
\node (customer) [def, draw, below left=of origin] {Customer};
|
\draw [<-, C] (mint) -- (auditor) node [midway, above, sloped] (TextNode) {verify};
|
||||||
\node (merchant) [def, draw, below right=of origin] {Merchant};
|
|
||||||
|
|
||||||
\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}
|
\end{tikzpicture}
|
||||||
\caption{Taler's system model for the payment system is based on Chaum~\cite{chaum1983blind}.}
|
\caption{Taler's system model for the payment system is based on Chaum~\cite{chaum1983blind}.}
|
||||||
\label{fig:cmm}
|
\label{fig:cmm}
|
||||||
@ -777,13 +779,78 @@ and $G$ is the generator of the elliptic curve.
|
|||||||
|
|
||||||
\subsection{Linking}
|
\subsection{Linking}
|
||||||
|
|
||||||
% FIXME: explain better...
|
For a coin that was successfully refreshed, the mint responds to a
|
||||||
For a coin that was successfully refreshed, the mint responds to
|
request $S_{C'}(\mathtt{link})$ with $(T^{(\gamma)}_p$, $E_{\gamma},
|
||||||
a request $S_{C'}(\mathtt{link})$ with $(T^{(\gamma)}_p$, $E_{\gamma}, \widetilde{C})$.
|
\widetilde{C})$.
|
||||||
|
|
||||||
This allows the owner of the old coin to also obtain the private key
|
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
|
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}
|
\subsection{Refunds}
|
||||||
|
|
||||||
@ -849,15 +916,15 @@ transfer.
|
|||||||
%suitable for money laundering, we are optimistic that states will find
|
%suitable for money laundering, we are optimistic that states will find
|
||||||
%the design desirable.
|
%the design desirable.
|
||||||
|
|
||||||
We did not yet perform performance measurements for the various
|
We performed some initial performance measurements for the various
|
||||||
operations. However, we are pretty sure that the computational and
|
operations. The main conclusion was that the computational and
|
||||||
bandwidth cost for transactions described in this paper is likely
|
bandwidth cost for transactions described in this paper is smaller
|
||||||
small compared to other business costs for the mint. We expect costs
|
than $10^{-3}$ cent/transaction, and thus dwarfed by the other
|
||||||
within the system to be dominated by the (replicated, transactional)
|
business costs for the mint. However, this figure excludes the cost
|
||||||
database. However, these expenses are again likely small in relation
|
of currency transfers using traditional banking, which a mint operator
|
||||||
to the business cost of currency transfers using traditional banking.
|
would ultimately have to interact with. Here, mint operators should
|
||||||
Here, mint operators should be able to reduce their expenses by
|
be able to reduce their expenses by aggregating multiple transfers to
|
||||||
aggregating multiple transfers to the same merchant.
|
the same merchant.
|
||||||
|
|
||||||
|
|
||||||
\section{Conclusion}
|
\section{Conclusion}
|
||||||
@ -871,6 +938,15 @@ protocol may finally enable modern society to upgrade to proper
|
|||||||
electronic wallets with efficient, secure and privacy-preserving
|
electronic wallets with efficient, secure and privacy-preserving
|
||||||
transactions.
|
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}
|
\bibliographystyle{alpha}
|
||||||
\bibliography{taler}
|
\bibliography{taler}
|
||||||
|
|
||||||
@ -888,6 +964,7 @@ we expect that transactions with amounts below Taler's transaction
|
|||||||
costs to be economically meaningless. Nevertheless, we document
|
costs to be economically meaningless. Nevertheless, we document
|
||||||
various ways how this could be achieved.
|
various ways how this could be achieved.
|
||||||
|
|
||||||
|
|
||||||
\subsection{Incremental spending}
|
\subsection{Incremental spending}
|
||||||
|
|
||||||
For services that include pay-as-you-go billing, customers can over
|
For services that include pay-as-you-go billing, customers can over
|
||||||
|
@ -186,21 +186,74 @@ free_refresh_commit_coins_array(struct TALER_MINTDB_RefreshCommitCoin
|
|||||||
GNUNET_free (commit_coins);
|
GNUNET_free (commit_coins);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#define MELT_NEW_COINS 5
|
||||||
|
|
||||||
static int
|
static int
|
||||||
cmp_commit_coin_arrays (struct TALER_MINTDB_RefreshCommitCoin *a,
|
test_refresh_commit_coins (struct TALER_MINTDB_Session *session,
|
||||||
struct TALER_MINTDB_RefreshCommitCoin *b,
|
struct TALER_MINTDB_RefreshSession *refresh_session,
|
||||||
unsigned int size)
|
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_MINTDB_RefreshCommitCoin *a_ccoin;
|
||||||
struct TALER_RefreshLinkEncrypted *a_rlink;
|
struct TALER_RefreshLinkEncrypted *a_rlink;
|
||||||
struct TALER_MINTDB_RefreshCommitCoin *b_ccoin;
|
struct TALER_MINTDB_RefreshCommitCoin *b_ccoin;
|
||||||
struct TALER_RefreshLinkEncrypted *b_rlink;
|
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];
|
struct TALER_MINTDB_RefreshCommitCoin *ccoin;
|
||||||
b_ccoin = &b[cnt];
|
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 (a_ccoin->coin_ev_size != b_ccoin->coin_ev_size);
|
||||||
FAILIF (0 != memcmp (a_ccoin->coin_ev,
|
FAILIF (0 != memcmp (a_ccoin->coin_ev,
|
||||||
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,
|
b_rlink->coin_priv_enc,
|
||||||
sizeof (a_rlink->coin_priv_enc)));
|
sizeof (a_rlink->coin_priv_enc)));
|
||||||
}
|
}
|
||||||
return GNUNET_OK;
|
ret = GNUNET_OK;
|
||||||
|
|
||||||
drop:
|
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)
|
test_melting (struct TALER_MINTDB_Session *session)
|
||||||
{
|
{
|
||||||
#define MELT_OLD_COINS 10
|
#define MELT_OLD_COINS 10
|
||||||
#define MELT_NEW_COINS 5
|
|
||||||
|
|
||||||
struct TALER_MINTDB_RefreshSession refresh_session;
|
struct TALER_MINTDB_RefreshSession refresh_session;
|
||||||
struct TALER_MINTDB_RefreshSession ret_refresh_session;
|
struct TALER_MINTDB_RefreshSession ret_refresh_session;
|
||||||
struct GNUNET_HashCode session_hash;
|
struct GNUNET_HashCode session_hash;
|
||||||
@ -242,10 +298,6 @@ test_melting (struct TALER_MINTDB_Session *session)
|
|||||||
struct TALER_MINTDB_RefreshMelt *melts;
|
struct TALER_MINTDB_RefreshMelt *melts;
|
||||||
struct TALER_DenominationPublicKey *new_denom_pubs;
|
struct TALER_DenominationPublicKey *new_denom_pubs;
|
||||||
struct TALER_DenominationPublicKey *ret_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;
|
unsigned int cnt;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
@ -255,8 +307,6 @@ test_melting (struct TALER_MINTDB_Session *session)
|
|||||||
melts = NULL;
|
melts = NULL;
|
||||||
new_dkp = NULL;
|
new_dkp = NULL;
|
||||||
new_denom_pubs = NULL;
|
new_denom_pubs = NULL;
|
||||||
commit_coins = NULL;
|
|
||||||
ret_commit_coins = NULL;
|
|
||||||
/* create and test a refresh session */
|
/* create and test a refresh session */
|
||||||
refresh_session.num_oldcoins = MELT_OLD_COINS;
|
refresh_session.num_oldcoins = MELT_OLD_COINS;
|
||||||
refresh_session.num_newcoins = 1;
|
refresh_session.num_newcoins = 1;
|
||||||
@ -358,61 +408,15 @@ test_melting (struct TALER_MINTDB_Session *session)
|
|||||||
(ret_denom_pubs[cnt].rsa_public_key,
|
(ret_denom_pubs[cnt].rsa_public_key,
|
||||||
new_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 !=
|
FAILIF (GNUNET_OK !=
|
||||||
plugin->insert_refresh_commit_coins (plugin->cls,
|
test_refresh_commit_coins (session,
|
||||||
session,
|
&refresh_session,
|
||||||
&session_hash,
|
&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));
|
|
||||||
ret = GNUNET_OK;
|
ret = GNUNET_OK;
|
||||||
|
|
||||||
drop:
|
drop:
|
||||||
destroy_denom_key_pair (dkp);
|
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)
|
if (NULL != melts)
|
||||||
{
|
{
|
||||||
for (cnt = 0; cnt < MELT_OLD_COINS; cnt++)
|
for (cnt = 0; cnt < MELT_OLD_COINS; cnt++)
|
||||||
|
Loading…
Reference in New Issue
Block a user