exchange/doc/system/taler/implementation.tex
Christian Grothoff 5106a09c9f
fix more typos
2021-04-23 23:53:52 +02:00

2433 lines
127 KiB
TeX

\chapter{Implementation of GNU Taler}\label{chapter:implementation}
This chapter describes the implementation of GNU Taler in detail. Concrete
design decisions, protocol details and our reference implementation are
discussed.
We implemented the GNU Taler protocol in the context of a payment system for
the web, as shown in Figure~\ref{fig:taler-arch}. The system was designed for
real-world usage with current web technologies and within existing
financial systems.
The following technical goals and constraints influenced the design of the
concrete protocol and implementation:
\begin{itemize}
\item The implementation should allow payments in browsers with hardened
security settings. In particular, it must be possible to make a payment
without executing JavaScript on a merchant's website and without having to
store (session-)cookies or requiring a login.
\item Cryptographic evidence should be available to all parties in case of a
dispute.
\item In addition to the guarantees provided by the GNU Taler protocol, the
implementation must take care to not introduce additional threats to
security and privacy. Features that trade privacy for convenience should
be clearly communicated to the user, and the user must have the choice to
deactivate them. Integration with the web should minimize the potential
for additional user tracking.
\item The integration for merchants must be simple. In particular, merchants
should not have to write code involving cryptographic operations or have to
manage Taler-specific secrets in their own application processes.
\item The web integration must not be specific to a single browser platform, but
instead must be able to use the lowest common denominator of what is
currently available. User experience enhancements supported for only
specific platforms are possible, but fallbacks must be provided for other
platforms.
\item URLs should be clean, user-friendly and must have the expected
semantics when sharing them with others or revisiting them after a session
expired.
\item Multiple currencies must be supported. Conversion between
different currencies is out of scope.
\item The implementation should offer flexibility with regards to what
context or applications it can be used for. In particular, the
implementation must make it possible to provide plugins for different
underlying banking systems and provide hooks to deal with different
regulatory requirements.
\item The implementation must be robust against network failures and crash
faults, and recover as gracefully as possible from data loss. Operations
must be idempotent if possible, e.g., accidentally clicking a payment button twice should
only result in one payment, and refreshing a page should not lead to
failures in the payment process.
\item Authorization should be preferred to authentication. In particular,
there should be no situations in which the user must enter confidential
information on a page that cannot be clearly identified as secure.
\item No flickering or unnecessary redirects. To complete a payment, the
number of request, especially in the user's navigation context, should be
minimized.
\item While the implementation should integrate well with browsers, it must
be possible to request and make payments without a browser. This makes at
least part of the implementation completely independent of the extremely
complex browser standards, and makes Taler usable for machine-to-machine
payments.
%\item Backwards compatibility (with what?)
\end{itemize}
We now recapitulate how a GNU Taler payment works, with some more details
specific to the implementation.
By instructing their bank to send money to an exchange, the customer creates a
(non-anonymous) balance, called a \emph{reserve}, at the exchange. Once the
exchange has received and processed the bank transfer, the customer's
\emph{wallet} automatically \emph{drains} the reserve by withdrawing coins from
it until the reserve is empty. Withdrawing immediately before a purchase should
be avoided, as it decreases the customer's anonymity set by creating a
correlation between the non-anonymous withdrawal and the spending.
To withdraw coins from the exchange, the customer's wallet authenticates itself
using an Ed25519 private key for the customer's reserve. The customer must
include the corresponding reserve public key in the payment instruction from
the customer's bank to the exchange's bank that funded their reserve. With a
bank that directly supports Taler on their online banking website, this process
is streamlined for the user, since the wallet automatically creates the key
pair for the reserve and adds the public key to the payment instruction.
While browsing a merchant's website, the website can signal the wallet to
request a payment from a user. The user is then asked to confirm or reject this
proposal. If the user accepts, the wallet spends coins with the merchant. The
merchant deposits coins received from the customer's wallet at the exchange.
Since bank transfers are usually costly, the exchange delays and aggregates
multiple deposits into a bigger wire transfer. This allows GNU Taler to be
used even for microtransactions of amounts smaller than usually handled by the
underlying banking system.
\begin{figure}
\includegraphics[width=\columnwidth]{taler-arch-full.pdf}
\caption[Components of GNU Taler in the context of a banking system.]{The different components of the Taler system in the
context of a banking system providing money creation,
wire transfers and authentication. (Auditor omitted.)}
\label{fig:taler-arch-full}
\end{figure}
As shown in Figure~\ref{fig:taler-arch-full}, the merchant is internally split
into multiple components. The implementation of the Taler protocol and
cryptographic operations is isolated into a separate component, called the
\emph{merchant backend}, which the merchant accesses through an API or software
development kit (SDK) in the programming language of their choice.
Our implementations of the exchange (70,000 LOC) and merchant backend
(20,000 LOC) are written in C using PostgreSQL as the database and
libgcrypt for cryptographic operations. The \emph{wallet} (10,000
LOC) is implemented in TypeScript as a cross-browser extension using
the WebExtensions API, which is available for a majority of widely
used browsers. It also uses libgcrypt (compiled to JavaScript) for
cryptographic operations as the required primitives are not yet
natively supported by web browsers. Sample merchant websites (1,000
LOC) and an example bank (2,000 LOC) with tight Taler integration are
provided in Python.
The code is available at \url{https://git.taler.net/} and a demo
is publicly available at \url{https://demo.taler.net/}.
\section{Overview}
We provide a high-level overview over the implementation,
before discussing the respective components in detail.
\subsection{Taler APIs}
The components of Taler communicate over an HTTP-based, RESTful\footnote{
Some REST purists might disagree, because the Taler APIs do not follow
all REST principles religiously. In particular, the HATEOAS principle is not followed.
} \cite{fielding2000architectural}
API. All request payloads and responses are JSON \cite{rfc8259} documents.
Binary data (such as key material, signatures and hashes) is encoded as a
base32-crockford \cite{crockford_base32} string. Base32-crockford is a simple,
case-insensitive encoding of binary data into a subset of the ASCII alphabet
that encodes 5 bits per character. While this is not the most space-efficient
encoding, it is relatively resilient against human transcription errors.
Financial amounts are treated as fixed-point decimal numbers. The
implementation internally uses a pair of integers $(v,f)$ with value part $0
\le v \le 2^{52}$ and fractional part $0 \le f < 10^8$ to represent the amount
$a = v + f\cdot 10^{-8}$. This representation was chosen as the smallest
representable amount is equal to one Satoshi (the smallest representable amount
in Bitcoin), and the largest possible value part (besides being large enough
for typical financial applications) is still accurately representable in 64-bit
IEEE 754 floating point numbers. These constraints are useful as some
languages such as JavaScript\footnote{Big integers are currently in the process
of being added to the JavaScript language standard.} provide IEEE 753 floating
point numbers as the only numeric type. More importantly, fixed-point decimal
numbers allow exact representation of decimal values (say \EUR{0.10}), which
is not possible with floating point numbers but essential in financial applications.
Signatures are made over custom binary representations of the respective
values, prefixed with a 64-bit tag consisting of the size of the message (32
bits) and an integer tag (32 bits) uniquely identifying the purpose of the message.
To sign a free-form JSON object, a canonical representation as a string is
created by removing all white space and sorting objects' fields.
In the future, more space-efficient representations (such as BSON\footnote{http://bsonspec.org/} or CBOR \cite{rfc7049})
could be used. The representation can be negotiated between client and server
in a backwards-compatible way with the HTTP ``Accept'' header.
% signatures!
\subsection{Cryptographic Algorithms}
The following cryptographic primitives are used by Taler:
\begin{itemize}
\item SHA512 \cite{rfc4634} as a cryptographic hash function
\item Ed25519 \cite{bernstein2006curve25519} for non-blind signing operations
\item Curve25519 \cite{bernstein2006curve25519} for the refreshing operation
\item HKDF \cite{rfc5869} as a key derivation function for the refreshing operation
\item FDH-RSA blind signatures \cite{bellare2003onemore}
\end{itemize}
We chose these primitives as they are simple, cheap enough and relatively well
studied. Note that other signature schemes that have the syntax and properties
described in Section~\ref{sec:crypto:instantiation}, such as
\cite{boldyreva2003threshold}, could be used instead of FDH-RSA.
\subsection{Entities and Public Key Infrastructure}
\begin{figure}
\includegraphics[width=\textwidth]{diagrams/taler-diagram-signatures.png}
\caption[Entities/PKI in Taler]{Entities/PKI in Taler. Solid arrows denote signatures, dotted arrows denote blind signatures.}
\end{figure}
The public key infrastructure (PKI) used by Taler is orthogonal to the PKI used
by TLS \cite{rfc5246}. While TLS is used as the transport layer for Taler API
messages, we do not rely on TLS for authenticity or integrity of API queries
and responses. We do rely on TLS for the confidentiality of digital business
contracts and the authenticity, integrity and confidentiality of digital
product delivery. For the anonymity properties to hold, the customer must
access the merchant and exchange through an anonymity layer (approximated
by practical implementations like Tor \cite{dingledine2004tor}).
In the case of merchants, we cannot use a trusted auditor or exchange as a
trust anchor, since merchants are not required to register within our PKI to
accept Taler payments. Here we rely on TLS instead: The merchant is required
to include their Taler-specific merchant public key in their TLS certificate.
If a merchant fails to do this, the wallet will show a warning when asking the
user to confirm a payment.
\subsubsection{Auditor}
Auditors serve as trust anchors for Taler, and are identified by a single Ed25519 public key.
Wallet implementations come with a pre-defined list of trusted auditors, similar to the certificate
store of browsers or operating systems.
\subsubsection{Exchange}
An exchange is identified by a long term Ed25519 master key and the exchange's
base URL. The master key is used as an offline signing key, typically stored
on an air-gapped machine. API requests to the exchange are made by appending
the name of the endpoint to the base URL.
The exchange uses the master key to sign the following data offline:
\begin{itemize}
\item The exchange's online Ed25519 signing keys. The online signing keys
are used to sign API responses from the exchange. Each signing key has a
validity period.
\item The denominations offered by the exchange (explained further in Section~\ref{sec:implementation:denoms}).
\item The bank accounts supported by the exchange (for withdrawals and deposits) and associated fees.
\end{itemize}
% FIXME: maybe put this later?
The \texttt{<base-url>/keys} HTTP endpoint of the exchange is used by wallets
and merchants to obtain the exchange's signing keys, currently offered
denominations and other details. In order to reduce traffic, clients can also
request only signing keys and denominations that were created after a specific
time. The response to \texttt{/keys} is signed by a currently active signing
key, so that customers would have proof in case the exchange gave different sets of
denomination keys to different customers in an attempt to deanonymize them.
\begin{figure}
\begin{multicols}{2}
\lstinputlisting[language=C,basicstyle=\ttfamily\tiny,numbers=left]{taler/snippet-keys.txt}
\end{multicols}
\caption{Example response for /keys}
\end{figure}
\subsubsection{Coins and Denominations}\label{sec:implementation:denoms}
Denominations are the RSA public keys used to blindly sign coins of a fixed amount, together with information about their
validity and associated fees. The following information is signed by the exchanges master key for every denomination:
\begin{itemize}
\item The RSA public key.
\item The start date, after which coins of this denomination can be withdrawn and deposited.
\item The withdraw expiration date, after which coins cannot be withdrawn anymore, must be after the start date.
\item The deposit expiration date, after which coins cannot be deposited anymore, must be after the withdraw expiration date.
\item The legal expiration date, after which the exchange can delete all records about operations with coins of this denominations,
must be (typically quite a long time!) after the deposit expiration date.
\item The fees for a withdraw, deposit, refresh and refund operation with this coin, respectively.
\end{itemize}
\begin{figure}
\centering
\includegraphics[width=0.7\textwidth]{diagrams/taler-diagram-denom-expiration.png}
\caption{A denomination's lifetime.}
\end{figure}
An exchange can be audited by zero, one or multiple auditors. An auditor must
monitor all denominations currently offered by the exchange, and an audit of a
subset of denominations is not intended in the current design. To allow
customers of an exchange to confirm that it is audited properly, the auditor
signs an auditing request from the exchange, containing basic information about
the exchange as well as all keys offered during the auditing period. In
addition to the full auditing request, the auditor also signs an individual
certificate for each denomination individually, allowing clients of the
exchange to incrementally verify newly offered denominations.
\subsubsection{Merchant}
The merchant has one Ed25519 key pair that is used to sign responses to the
customer and authenticate some requests to the exchange. Depending on the
legislation that applies to a particular GNU Taler deployment, merchants might
not need to establish an a priori relationship with the exchange, but instead
send their bank account information during or after the first deposit of a
payment from a customer.
% FIXME: we never write here that the merchant accepts payments from all trusted auditors/exchanges
% automatically
% FIXME: citation for this?
% FIXME: are there jurisdictions where KYC would apply to the exchange's customer?
In some jurisdictions, exchanges are required to follow know-your-customer
(KYC) regulations and to verify the identity of merchants \cite{arner2018identity} using that particular
exchange for deposits. Typically, the identity of a merchant only has to be
verified if a merchant exceeds a certain threshold of transactions in a given
time span. As the KYC registration process can be costly to the exchange, this
requirement is somewhat at odds with merchants accepting payments from all
exchanges audited by a trusted auditor, since KYC registration needs to be done
at every exchange separately. It is, however, unavoidable to run a legally
compliant payment system.
A merchant is typically configured with a set of trusted auditors and
exchanges, and consequently accepts payments with coins of denominations from a
trusted exchange and denominations audited by a trusted auditor.
In order to make the deployment of Taler easier and more secure, the parts that
deal with the merchant's private key and cryptographic operations are isolated
into a separate service (the merchant backend) with a well-defined RESTful HTTP API.
This concept is similar to payment gateways used commonly for credit card
payments. The merchant backend can be deployed on-premise by the online shop,
or run by a third party provider that is fully trusted by the merchant.
\subsubsection{Bank}
Since the banks are third parties that are not directly part of Taler, they do
not participate directly in Taler's PKI.
\subsubsection{Customer}
Customers are not registered with an exchange, instead they use the private
keys of reserves that they own to authenticate with the exchange. The exchange
knows the reserve's public key from the subject/instruction data of the wire
transfer. Wire transfers that do not contain a valid public key are
automatically reversed.
\subsection{Payments}
\newlength{\maxheight}
\setlength{\maxheight}{\heightof{\small W}}
\newcommand{\bffmt}[1]{%
\footnotesize
\centering
\raisebox{0pt}[\maxheight][0pt]{#1}%
}
\begin{figure}
\centering
\begin{bytefield}[bitwidth=0.2em,bitheight=3ex,boxformatting=\bffmt]{128}
\bitheader{0,31,63,95,127} \\
\bitbox{32}{size} & \bitbox{32}{purpose} & \bitbox{64}{timestamp} \\
\wordbox{2}{merchant public key} \\
\wordbox{4}{contract terms hash} \\
\bitbox{64}{deposit deadline} & \bitbox{64}{refund deadline} \\
\wordbox{4}{KYC / account info hash}
\end{bytefield}
\caption{The contract header that is signed by the merchant.}
\end{figure}
\begin{figure}
\centering
\begin{bytefield}[bitwidth=0.2em,bitheight=3ex,boxformatting=\bffmt]{128}
\bitheader{0,31,63,95,127} \\
\bitbox{32}{size} & \bitbox{32}{purpose} & \bitbox{64}{timestamp} \\
\wordbox{4}{contract header hash} \\
\wordbox{2}{coin public key} \\
\bitbox[lrt]{128}{contributed amount} \\
\bitbox[lrb]{64}{} & \bitbox[ltr]{64}{} \\
\bitbox[lrb]{128}{deposit fee} \\
\end{bytefield}
\caption{The deposit permission signed by the customer's wallet.}
\end{figure}
Payments in Taler are based on \emph{contract terms}, a JSON object that
describes the subject and modalities of a business transaction. The
cryptographic hash of such a contract terms object can be used as a globally
unique identifier for the business transaction. Merchants must sign the
contract terms before sending them to the customer, allowing a customer to
prove in case of a dispute the obligations of the merchant resulting from the
payment.
Unless a third party needs to get involved in a dispute, it is sufficient (and
desirable for data minimization) that only the merchant and the customer know
the full content of the contract terms. The exchange, however, must still
know the parts of the contract terms that specify payment modalities, such as
the refund policy, micropayment aggregation deadline and the merchant's KYC
registration data (typically a hash to prove the KYC enrollment of the
merchant).
Thus, the merchant's signature is made over the \emph{contract header},
which contains the contract terms hash, as well as the payment modalities.
In addition to the data provided by the merchant, the contract terms contain a
\emph{claim\_pub} field whose value is provided by the customer.
This field is an Ed25519 public key, and the customer can use the corresponding
private key to prove that they have indeed obtained the individual contract
terms from the merchant, and did not copy contract terms that the merchant gave
to another customer. Note that this key is not a permanent identity of the
customer, but should be freshly generated for each payment.
The signed contract header is created by the merchant's backend from an
\emph{order}, which is the ``blueprint'' for the contract terms. The order is
generated by the merchant's frontend and contains a subset of the data
contained in the contract terms. Missing data (in particular the merchant's
bank account information, public key and accepted auditors/exchanges) and
the claim public key obtained from the customer is automatically added by the merchant
backend. This allows applications to process payments without having to
specify Taler-internal details. In fact, the smallest possible order only
needs to contain two fields: the amount to be paid and a human-readable
summary of the payment's subject.
An order contains an \emph{order ID}, which is an identifier that is unique
within a given merchant and can be a human-friendly identifier such as a
booking number. If the order ID is not manually provided, it is automatically
filled in by the merchant backend. It can be used to refer to the payment
associated with the order without knowing the contract terms hash, which is
only available once the customer has provided their claim public key.
To initiate a payment, the merchant sends the customer an \emph{unclaimed}
contract terms URL. The customer can download and thereby claim ownership of
the contract by appending their claim public key $p$ as a query parameter to the unclaimed
contract terms URL and making an HTTP \texttt{GET} request to the resulting URL.
The customer must then verify that the resulting contract terms are signed
correctly by the merchant and that the contract terms contain their claim public key $p$.
A malicious customer could try to claim other customers' contracts by guessing
contract term URLs and appending their own claim public key. For products that have
limited availability, the unclaimed contract URL must have enough entropy so
that malicious customers are not able to guess them and claim them before the
honest customer.\footnote{Note that this URL cannot be protected by a session
cookie, as it might be requested from a different session context than the
user's browser, namely in the wallet.}
% FIXME: put this in a sidebox?
To give an example, an online shop for concert tickets might allow users to put
themselves on a waiting list, and will send them an email once a ticket
becomes available. The contract terms URL that allows the customer to purchase
the ticket (once they have visited a link in this email), should contain an
unguessable nonce, as otherwise an attacker might be able to predict the URL
and claim the contract for the concert ticket before the customer's wallet can.
In order to settle the payment, the customer must sign a \emph{deposit
permission} for each coin that comprises the payment. The deposit permission
is a message signed by the coin's private key, containing
\begin{itemize}
\item the amount contributed by this coin to the payment,
\item the merchant's public key
\item the contract header together with the merchant's signature on it,
\item the time at which the deposit permission was signed.
\end{itemize}
After constructing the deposit permissions for a contract, the customer sends
them to the merchant by doing an HTTP \texttt{POST} request to the
\texttt{pay\_url} indicated by the merchant in the contract terms. The
merchant individually \emph{deposits} each deposit permission with the
exchange.
The merchant responds with a payment confirmation to the customer after it has
successfully deposited the customer's coins with the exchange. The payment
confirmation can be used by the customer to prove that they completed the
payment before the payment deadline indicated in the contract terms.
Note that the depositing multiple coins with the exchange deliberately does not
have transactional semantics. Instead, each coin is deposited in an individual
transaction. This allows the exchange to be horizontally scaled (as discussed
in Section~\ref{sec:implementation-improvements}) more easily, as deposit
transaction might otherwise have to span multiple database shards.
The lack of transactional semantics, however, means that it must be possible to
recover from partially completed payments. There are several cases: If one of
the coins that the customer submitted as payment to the merchant is invalid
(e.g., because the wallet's state was restored from a backup), the customer can
re-try the partially completed payment and provide a different coin instead.
If that is not possible or desired by the customer, the merchant may voluntarily give a
refund on the coins that have been previously deposited. The reference
implementation of the merchant backend offers refunds for partially completed
payments automatically.
% FIXME: explain why!
If refunds were disabled for the payment, the merchant does not cooperate in
giving refunds for a partially completed payment, or becomes unresponsive after
partially depositing the customer's coin, the customer has two options: They
can either complete the deposits on the merchant's behalf, and then use the
deposit permissions to prove (either to the merchant or to a court) that they
completed the payment.
% FIXME: put this in info box?
Another possibility would be to allow customers to request refunds for partially
completed payments themselves, directly from the exchange.
This requires that the merchant additionally
includes the amount to be paid for the contract in the contract header, as the
exchange needs to know that amount to decide if a payment with multiple coins
is complete. We do not implement this approach, since it implies that the
exchange always learns the exact prices of products that the merchant sells, as
opposed to just the merchant's total revenue.
The customer could also reveal the contract terms to the exchange to prove that
a payment is incomplete, but this is undesirable for privacy reasons, as the
exchange should not learn about the full details of the business agreement
between customer and merchant.
\subsection{Resource-based Web Payments}
In order to integrate natively with the concepts and architecture of the web,
Taler supports paying for a web resource in the form of a URL. In fact all
Taler contract terms contain a \emph{fulfillment URL}, which identifies the
resource that is being paid for. If the customer is not paying for a digital
product (such as an movie, song or article), the fulfillment URL can point to a
confirmation page that shows further information, such as a receipt for a
donation or shipment tracking information for a physical purchase. A
fulfillment URL does not necessarily refer to a single item, but could also
represent a collection such as a shopping basket.
The following steps illustrate a typical payment with the online shop
\nolinkurl{alice-shop.example.com}.
\newcommand{\contl}[0]{\mbox{\textcolor{blue}{$\hookrightarrow$}\space}}
\lstdefinelanguage{none}{
identifierstyle=
}
\lstdefinestyle{myhttp}{
breaklines=true,
breakindent=3em,
escapechar=*,
postbreak=\contl,
basicstyle=\ttfamily,
showspaces=true,
}
\begin{enumerate}
\item The user opens the shop's page and navigates to a paid resource, such
as \nolinkurl{https://alice-shop.example.com/essay-24.pdf}.
\item The shop sends a response with HTTP status ``402 Payment Required''
with the headers (\contl marks a continued line)
\begin{lstlisting}[style=myhttp]
Taler-Contract-Url: https://alice-shop.example.com/*\break\contl*contract?product=essay-24.pdf
Taler-Resource-Url: https://alice-shop.example.com/*\break\contl*essay-24.pdf
\end{lstlisting}
\item Since the user's wallet does not yet contain contract terms with the
fulfillment URL \nolinkurl{https://alice-shop.example.com/esasy-24.pdf}
that matches the resources URL, it claims the contract by generating a
claim key pair $(s, p)$ and requesting the contract URL with the claim
public key $p$ as additional parameter:
\nolinkurl{https://alice-shop.example.com/contract?product=essay-24.pdf\&claim_pub=}$p$.
\item The wallet displays the contract terms to the customer and asks them to
accept or decline. If the customer accepted the contract, the wallet sends
a payment to the merchant. After the merchant received a valid payment,
it marks the corresponding order as paid.
\item The wallet constructs the extended fulfillment URL by adding the order
id from the contract as an additional parameter and navigates the browser
to the resulting URL
\nolinkurl{https://alice-shop.example.com/esasy-24.pdf?order\_id=...}.
\item The shop receives the request to the extended fulfillment URL and
checks if the payment corresponding to the order ID was completed. In case
the payment was successful, it serves the purchased content.
\end{enumerate}
To avoid checking the status of the payment every time, the merchant can
instead set a session cookie (signed/encrypted by the merchant) in the user's
browser which indicates that \texttt{essay-24.pdf} has been purchased.
The resource-based payment mechanism must also handle the situation where a
customer navigates again to a resource that they already paid for, without
directly navigating to the extended fulfillment URL. In case no session cookie
was set for the purchase or the cookie was deleted / has expired, the customer would
be prompted for a payment again. To avoid this, the wallet tries to find an
existing contract whose plain fulfillment URL matches the resource URL
specified in the merchant's HTTP 402 response. If such an existing payment was
found, the wallet instead redirects the user to the extended fulfillment URL
for this contract, instead of downloading the new contract terms and prompting
for payment.
In the example given above, the URL that triggers the payment is the same as the fulfillment URL.
This may not always the case in practice. When the merchant backend is hosted by a third
party, say \nolinkurl{https://bob.example.com/}, the page that triggers the payment
even has a different origin, i.e., the scheme, host or port may differ \cite{rfc6454}.
This cross-origin operation presents a potential privacy risk if not
implemented carefully.
To check whether a user has already paid for a particular
resource with URL $u$, an arbitrary website could send an HTTP 402 response with
the ``Taler-Resource-Url'' header set to $u$ and the ``Taler-Contract-Url''
set to a URL pointing to the attacker's server. If the user paid for $u$, the
wallet will navigate to the extended fulfillment URL corresponding to $u$.
Otherwise, the wallet will try to download a contract from the URL given by the
attacker. In order to prevent this attack on privacy, the wallet must only
redirect to $u$ if the origin of the page responding with HTTP 402 is the same
origin as either the $u$ or the pay URL.\footnote{This type of countermeasure is well
known in browsers as the same origin policy, as also outlined in \cite{rfc6454}.}
\subsubsection{Loose Browser Integration}\label{sec:loose-browser-integration}
The payment process we just described does not directly work in browsers that do not
have native Taler integration, as the browser (or at least a browser extension)
would have to handle the HTTP status code 402 and handle the Taler-specific headers correctly.
We now define a fallback, which is transparently implemented in the reference merchant backend.
In addition to indicating that a payment is required for a resource in the HTTP status code and header,
the merchant includes a fallback URL in the body of the ``402 Payment Required'' response. This URL must have the custom URL scheme
\texttt{taler}, and contains the contract terms URL (and other Taler-specific settings normally specified in headers)
as parameters. The above payment would include a link (labeled, e.g., ``Pay with GNU Taler'') to the following URL, encoding
the same information as the headers:
\begin{lstlisting}[style=myhttp]
taler:pay?*\break\contl*contract_url=*\break\contl*https%3A%2F%2Falice-shop.example.com%2Fcontract%3Fproduct%3Dessay-24.pdf*\break\contl*&resource_url=*\break\contl*https%3A%2F%2Falice-shop.example.com%2Fessay-24.pdf
\end{lstlisting}
This fallback can be disabled for requests from user agents that are known to
natively support GNU Taler.
GNU Taler wallet applications register themselves as a handler for the
\texttt{taler} URI scheme, and thus following a \texttt{taler:pay} link opens
the dedicated wallet, even if GNU Taler is not supported by the browser or a
browser extension. Registration a custom protocol handler for a URI scheme is
possible on all modern platforms with web browsers that we are aware of.
Note that wallets communicating with the merchant do so from a different
browsing context, and thus the merchant backend cannot rely on cookies that
were set in the customer's browser when using the shop page.
We chose HTTP headers as the primary means of signaling to the wallet (instead
of relying on, e.g., a new content media type), as it allows the fallback content
to be an HTML page that can be rendered by all browsers. Furthermore,
current browser extension mechanism allow intercepting headers synchronously
before the rendering of the page is started, avoiding visible flickering caused by
intermediate page loads.
\subsection{Session-bound Payments and Sharing}
As we described the payment protocol so far, an extended fulfillment URL
is
not bound to a browser session. When sharing an extended fulfillment
URL, another user would get access to the same content. This might be appropriate
for some types of fulfillment pages (such as a donation receipt), but is generally not
appropriate when digital content is sold. Even though it is trivial to share digital content
unless digital restrictions management (DRM) is employed, the ability to share
links might set the bar for sharing too low.
While the validity of a fulfillment URL could be limited to a certain time,
browser session or IP address, this would be too restrictive for scenarios where
the user wants to purchase permanent access to the content.
As a compromise, Taler provides \emph{session-bound} payments. For
session-bound payments, the seller's website assigns the user a random session
ID, for example, via a session cookie. The extended fulfillment URL for
session-bound payments is constructed by additionally specifying the URL
parameter \texttt{session\_sig}, which contains proof that the user completed
(or re-played) the payment under their current session ID.
To initiate a session-bound payment, the HTTP 402 response must additionally
contain the ``Taler-Session-Id'' header, which will cause the wallet to
additionally obtain a signature on the session ID from the merchant's pay URL,
by additionally sending the session ID when executing (or re-playing) the
payment.
As an optimization, instead of re-playing the full payment, the wallet can also
send the session ID together with the payment receipt it obtained from the
completed payment with different session ID.
Before serving paid content to the user, the merchant simply checks if the
session signature matches the assigned session and contract terms. To simplify
the implementation of the frontend, this signature check can be implemented as
a request to the GNU Taler backend. Using session signatures instead of storing
all completed session-bound payments in the merchant's database saves storage.
While the coins used for the payment or the payment receipt could be shared
with other wallets, it is a higher barrier than just sharing a URL. Furthermore, the
merchant could restrict the rate at which new sessions can be created for the
same contract terms and restrict a session to one IP address, limiting sharing.
For the situation where a user accesses a session-bound paid resource and
neither has a corresponding contract in their wallet nor does the merchant
provide a contract URL to buy access to the resource, the merchant can specify
an \emph{offer URL} in the ``Taler-Offer-Url'' header. If the wallet is not
able to take any other steps to complete the payment, it will redirect the user
to the offer URL. As the name suggests, the offer URL can point to a page with
alternative offers for the resource, or some other explanation as to why the
resource is not available anymore.
\subsection{Embedded Content}
So far we only considered paying for a single, top-level resource,
namely the fulfillment URL. In practice, however, websites are composed of
many subresources such as embedded images and videos.
We describe two techniques to ``paywall'' subresources behind a GNU Taler
payment. Many other approaches and variations are possible.
\begin{enumerate}
\item Visiting the fulfillment URL can set a session cookie. When a
subresource is requested, the server will check that the customer has the
correct session cookie set.
\item When serving the fulfillment page, the merchant can add an additional
authentication token to the URLs of subresources. When the subresource is
requested, the validity of the authentication token is checked. If the
merchant itself (instead of a Content Delivery Network that supports token
authentication) is serving the paid subresource, the order ID and session
signature can also be used as the authentication token.
\end{enumerate}
It would technically be possible to allow contract terms to refer to multiple
resources that are being purchased by including a list or pattern that defines
a set of URLs. The browser would then automatically include information to
identify the completed payment in the request for the subresource. We
deliberately do not implement this approach, as it would require deeper
integration in the browser than possible on many platforms. If not restricted
carefully, this feature could also be used as an additional method to track the
user across the merchant's website.
\subsection{Contract Terms}
The contract terms, only seen by the customer and the merchant (except when a tax audit of the merchant is requested)
contain the following information:
\begin{itemize}
\item The total amount to be paid,
\item the \texttt{pay\_url}, an HTTP endpoint that receives the payment,
\item the deadline until the merchant accepts the payment (repeated in the signed contract header),
\item the deadline for refunds (repeated in the signed contract header),
\item the claim public key provided by the customer, used to prove they have claimed the contract terms,
\item the order ID, which is a short, human-friendly identifier for the contract terms within
the merchant,
\item the \texttt{fulfillment\_url}, which identifies the resources that is being paid for,
\item a human-readable summary and product list,
\item the fees covered by the merchant (if the fees for the payment exceed this value, the
customer must explicitly pay the additional fees),
\item depending on the underlying payment system, KYC registration information
or other payment-related data that needs to be passed on to the exchange (repeated in the signed contract header),
\item the list of exchanges and auditors that the merchants accepts for the payment,
\item information about the merchant, including the merchant public key and contact information.
\end{itemize}
\subsection{Refunds}
By signing a \emph{refund permission}, the merchant can ``undo'' a deposit on a
coin, either fully or partially. The customer can then spend (or refresh) the
refunded value of the coin again. A refund is only possible before the refund
deadline (specified in the contract header). After the refund deadline has
passed (and before the deposit deadline) the exchange makes a bank transfer the
merchant with the aggregated value from deposits, a refund after this point
would require a bank transfer back from the merchant to the exchange.
Each individual refund on each coin incurs fees; the
refund fee is subtracted from the amount given back to the customer and kept by
the exchange.
Typically a refund serves either one of the following purposes:
\begin{itemize}
\item An automatic refund is given to the customer when a payment only
partially succeeded. This can happen when a customer's wallet accidentally
double-spends, which is possible even with non-malicious customers and caused by data
loss or delayed/failed synchronization between the same user's wallet on
multiple devices. In these cases, the user can choose to re-try the
payment with different, unspent coins (if available) or to ask for a refund
from the merchant.
\item A voluntary refund can be given at the discretion of the merchant,
for example, when the customer is not happy with their purchase.
\end{itemize}
Refunds require a signature by the merchant, but no consent from the customer.
A customer is notified of a refund with the HTTP 402 Payment Required status
code and the ``Taler-Refund'' header. The value of the refund header is a
URL. An HTTP \texttt{GET} request on that URL will return a list of refund confirmations that the
merchant received from the exchange.
\subsection{Tipping}
Tipping in Taler uses the ``withdraw loophole'' (see \ref{taler:design:tipping}) to allow the
merchant\footnote{We still use the term ``merchant'', since donations use the same software component
as the merchant, but ``donor'' would be more accurate.} to donate small amounts (without any associated contract terms or legal
obligations) into the user's wallet.
To be able to give tips, the merchant must create a reserve with an exchange. The reserve private key
is used to sign blinded coins generated by the user that is being given the tip.
The merchant triggers the wallet by returning an HTTP 402 Payment Required
response that includes the ``Taler-Tip'' header. The value of the tip header (called the
tip token) contains
\begin{itemize}
\item the amount of the tip,
\item the exchange to use,
\item a URL to redirect after processing the tip,
\item a deadline for picking up the tip,
\item a merchant-internal unique ID for the tip, and
\item the \emph{pickup URL} for the tip.
\end{itemize}
Upon receiving the tip token, the wallet creates coin planchets that sum up to at most
the amount specified in the tip token, with denominations offered by the exchange specified in the tip token.
The list of planchets is then sent to the merchant via an HTTP \texttt{POST}
request to the tip-pickup URL. The merchant creates a withdrawal confirmation
signature for each planchet, using the private key of the tipping reserve, and
responds to the HTTP \texttt{POST} request with the resulting list of
signatures. The user then uses these signatures in the normal withdrawal
protocol with the exchange to obtain coins ``paid for'' by the merchant, but
anonymized and only spendable by the customer.
\section{Bank Integration}
In order to use Taler for real-world payments, it must be integrated with the
existing banking system. Banks can choose to tightly integrate with Taler and
offer the ability to withdraw coins on their website. Even existing banks can
be used to withdraw coins via a manual bank transfer to the exchange, with the
only requirement that the 52 character alphanumeric, case-insensitive encoding
of the reserve public key can be included in the transaction without
modification other than case folding and white space
normalization.\footnote{Some banking systems specify that the subject of the
can be changed, and provide an additional machine-readable ``instruction''
field. }
\subsection{Wire Method Identifiers}\label{implementation:wire-method-identifiers}
We introduce a new URI scheme \texttt{payto}, which is used in Taler to
identify target accounts across a wide variety of payment systems with uniform
syntax.
In in its simplest form, a \texttt{payto} URI identifies one account of a particular payment system:
\begin{center}
\texttt{'payto://' TYPE '/' ACCOUNT }
\end{center}
When opening a \texttt{payto} URI, the default action is to open an application
that can handle payments with the given type of payment system, with the target
account pre-filled. In its extended form, a \texttt{payto} URL can also specify
additional information for a payment in the query parameters of the URI.
In the generic syntax for URIs, the payment system type corresponds to the
authority, the account corresponds to the path, and additional parameters for
the payment correspond to the query parameters. Conforming to the generic URI
syntax makes parsing of \texttt{payto} URIs trivial with existing parsers.
Formally, a \texttt{payto} URI is an encoding of a partially filled out pro
forma invoice. The full specification of the \texttt{payto} URI is RFC XXXX. % FIXME!
In the implementation of Taler, \texttt{payto} URIs are used in various places:
\begin{enumerate}
\item The exchange lists the different ways it can accept money as \texttt{payto} URIs.
If the exchange uses payment methods that do not have tight Taler integration.
\item In order to withdraw money from an exchange that uses a bank account type that
does not typically have tight Taler integration, the wallet can generate a link and a QR code
that already contains the reserve public key. When scanning the QR code with a mobile device that
has an appropriate banking app installed, a bank transfer form can be pre-filled and the user only has to confirm the
transfer to the exchange.
\item The merchant specifies the account it wishes to be paid on as a \texttt{payto} URI, both in
the configuration of the merchant backend as well as in communication with the exchange.
\end{enumerate}
A major advantage of encoding payment targets as URIs is that URI schemes can be registered
with an application on most platforms, and will be ``clickable'' in most applications and open the right
application when scanned as a QR code. This is especially useful for the first use case listed above; the other use cases
could be covered by defining a media type instead \cite{rfc6838}.
% FIXME: put into side box
As an example, the following QR code would open a banking application that supports SEPA payments,
pre-filled with a 15\EUR{} donation to the bank account of GNUnet:
\begin{center}
\qrcode[hyperlink,height=5em]{payto://sepa/DE67830654080004822650?amount=EUR:15}
\end{center}
\subsection{Demo Bank}
For demonstration purposes and integration testing, we use our toy bank
implementation\footnote{\url{https://git.taler.net/bank.git}}, which might be
used in the future for regional currencies or accounting systems (e.g., for a
company cafeteria). The payment type identifier is \texttt{taler-bank}. The
authority part encodes the base URL of the bank, and the path must be the
decimal representation of a single integer between $1$ and $2^{52}$, denoting
the internal demo bank account number.
\subsection{EBICS and SEPA}
The Electronic Banking Internet Communication Standard\footnote{\url{http://www.ebics.org}} (EBICS) is a standard
for communicating with banks, and is widely used in Germany, France and
Switzerland, which are part of the Single European Payment Area (SEPA). EBICS
itself is just a container format. A commonly supported payload for EBICS is
ISO 2022, which defines messages for banking-related business processes.
Integration of GNU Taler with EBICS is currently under development, and would
allow Taler to be easily deployed in many European countries, provided that the
exchange provider can obtain the required banking license.
\subsection{Blockchain Integration}
Blockchains such as Bitcoin could also be used as the underlying financial
system for GNU Taler, provided that merchants and customers trust the exchange to be honest.
With blockchains that allow more complex smart contracts, the auditing
functionality could be implemented by the blockchain itself. In particular,
the exchange can be incentivized to operate correctly by requiring an initial
safety deposit to the auditing smart contract, which is distributed to
defrauded participants if misbehavior of the exchange is detected.
\section{Exchange}
\begin{figure}
\includegraphics[width=\textwidth]{diagrams/taler-diagram-exchange.png}
\caption{Architecture of the exchange reference implementation}
\end{figure}
The exchange consists of three independent processes:
\begin{itemize}
\item The \texttt{taler-exchange-httpd} process handles HTTP requests from clients,
mainly merchants and wallets.
\item The \texttt{taler-exchange-wirewatch} process watches for wire transfers
to the exchange's bank account and updates reserves based on that.
\item The \texttt{taler-exchange-aggregator} process aggregates outgoing transactions
to merchants.
\end{itemize}
All three processes exchange data via the same database. Only
\texttt{taler-exchange-httpd} needs access to the exchanges online signing keys
and denomination keys.
The database is accessed via a Taler-specific database abstraction layer.
Different databases can be supported via plugins; at the time of writing this,
only a PostgreSQL plugin has been implemented.
Wire plugins are used as an abstraction to access the account layer that Taler
runs on. Specifically, the \textit{wirewatch} process uses the plugin to monitor
incoming transfers, and the aggregator process uses the wire plugin to make
wire transfers to merchants.
The following APIs are offered by the exchange:
\begin{description}
\item[Announcing keys, bank accounts and other public information] The
exchange offers the list of denomination keys, signing keys, auditors,
supported bank accounts, revoked keys and other general information needed
to use the exchange's services via the \texttt{/keys} and \texttt{/wire}
APIs.
\item[Obtaining entropy] As we cannot be sure that all client-devices have
an adequate random number generator, the exchange offers the \texttt{/seed}
endpoint to download some high-entropy value. Clients should mix this
seed with their own, locally-generated entropy into an entropy pool.
\item[Reserve status and withdrawal] After having wired money to the exchange,
the status of the reserve can be checked via the \texttt{/reserve/\$RESERVE\_PUB/status} API. Since
the wire transfer usually takes some time to arrive at the exchange, wallets should periodically
poll this API, and initiate a withdrawal with \texttt{/reserve/\$RESERVE\_PUB/withdraw} once the exchange received the funds.
\item[Deposits and tracking] Merchants transmit deposit permissions they have received from customers
to the exchange via the \texttt{/coins/\$COIN\_PUB/deposit} API. Since multiple deposits are aggregated into one wire transfer,
the merchant additionally can use the exchange's \texttt{/transfers/\$WTID} API that returns the list of deposits for a wire transfer
identifier (WTID) included in the wire transfer to the merchant, as well as the \texttt{/deposits/\$H\_WIRE/\$MERCHANT\_PUB/\$H\_CONTRACT\_TERMS/\$COIN\_PUB} API to look up
which wire transfer included the payment for a given deposit.
\item[Refresh] Refreshing consists of two stages. First, using \texttt{/coins/\$COIN\_PUB/melt} an old, possibly dirty coin is melted and thus devaluted. The commitment made by the wallet during the melt and the resulting $\gamma$-challenge from the exchange are associated with a {\em refresh session}. Then, using \texttt{/refreshes/\$RCH/reveal} the wallet can answer the challenge and obtain fresh coins as change. Finally, \texttt{/coins/\$COIN\_PUB/link} provides the link deterrent against refresh abuse.
\item[Refunds] The refund API (\texttt{/coins/\$COIN\_PUB/refund}) can ``undo'' a deposit if the merchant gave their signature, and the aggregation deadline
for the payment has not occurred yet.
\item[Recoup] The recoup API (\texttt{/coins/\$COIN\_PUB/recoup}) allows customers to be compensated
for coins whose denomination key has been revoked. Customers must send either a full withdrawal transcript that
includes their private blinding factor, or a refresh transcript (of a refresh that had the revoked denominations as one of the targets)
that includes blinding factors. In the former case, the reserve is credited, in the latter case, the source coin of the
refresh is refunded and can be refreshed again.
\end{description}
New denomination and signing keys are generated and signed with the exchange's master
secret key using the \texttt{taler-exchange-keyup} utility, according to a key schedule
defined in the exchange's configuration. This process should be done on an air-gapped
offline machine that has access to the exchange's master signing key.
Generating new keys with \texttt{taler-exchange-keyup} also generates an
auditing request file, which the exchange should send its auditors. The auditors then
certify these keys with the \texttt{taler-auditor-sign} tool.
\begin{figure}
\includegraphics[width=\textwidth]{diagrams/taler-diagram-keyup.png}
\caption{Data flow for updating the exchange's keys.}
\label{figure:keyup}
\end{figure}
This process is illustrated in Figure~\ref{figure:keyup}.
\section{Auditor}
The auditor consists of several main components:
\begin{itemize}
\item the \texttt{taler-auditor-dbinit} tool to setup,
upgrade or garbage-collect an auditor's database,
\item the \texttt{taler-auditor-exchange} tool to add an
exchange to the list of audited exchanges,
\item the \texttt{taler-auditor-sign} tool to sign an exchange's
keys to affirm that the auditor is auditing this exchange,
\item an HTTP service (\texttt{taler-auditor-httpd}) which
receives deposit confirmations from merchants, and
\item the \texttt{taler-auditor} script which must be regularly
run to generate audit reports.
\end{itemize}
\subsection{Database synchronization}
FIXME: describe issue of how to synchronize exchange and auditor
databases, and how we solved it (once we did solve it!) here.
\subsection{The \texttt{taler-auditor} tool}
The \texttt{taler-auditor} script uses several helper processes. These helper
processes access the exchange's database, either directly (for
exchange-internal auditing as part if its operational security) or over a
replica (in the case of external auditors).
The \texttt{taler-auditor} script ultimately generates a report with the
following information:
\begin{itemize}
\item Do the operations stored in a reserve's history match the reserve's balance?
\item Did the exchange record outgoing transactions to the right merchant for
deposits after the deadline for the payment was reached?
\item Do operations recorded on coins (deposit, refresh, refund) match the remaining
value on the coin?
\item Do operations respect the expiration of denominations?
\item For a denomination, is the number of pairwise different coin public
keys recorded in deposit/refresh operations smaller or equal to the number
of blind signatures recorded in withdraw/refresh operations?
If this invariant is violated, the corresponding denomination must be revoked.
%\item Are signatures made by the exchange correct? (no, apparently we don't store signatures)
\item What is the income if the exchange from different fees?
\end{itemize}
\subsubsection{Report generation}
The \texttt{taler-auditor} script invokes its helper processes, each of
which generates a JSON file with the key findings. The master script then
uses Jinja2 templating to fill a LaTeX template with the key findings, and
runs \texttt{pdflatex} to generate the final PDF.
It is also possible to run the helper processes manually, and given that only
one of them requires read-only access to the bank account of the exchange,
this may be useful to improve parallelism or enhance privilege
separation. Thus, \texttt{taler-auditor} is really only a convenience script.
\subsubsection{Incremental processing}
The operation of all auditor helper processes is incremental. There is a separate
database to checkpoint the auditing progress and to store intermediate results
for the incremental computation. Most database tables used by the exchange are
append-only: rows are only added but never removed or changed. Tables that
are destructively modified by the exchange only store cached computations based
on the append-only tables. Each append-only table has a monotonically
increasing row ID. Thus, the auditor's checkpoint simply consists of the set of
row IDs that were last seen.
\subsubsection{The \texttt{taler-helper-auditor-aggregation}}
This tool checks that the exchange properly aggregates
individual deposits into wire transfers
(see Figure~\ref{fig:deposit:states}).
The list of invariants checked by this tool thus includes:
\begin{itemize}
\item That the fees charged by the exchange are those
the exchange provided to the auditor earlier, and that the
fee calculations (deposit fee, refund fee, wire fee)
are correct. Refunds are relevant because refunded amounts
are not included in the aggregate balance.
\item The sanity of fees, as fees may not exceed the contribution
of a coin (so the deposit fee cannot be larger than the
deposited value, and the wire fee cannot exceed the
wired amount). Similarly, a coin cannot receive refunds
that exceed the deposited value of the coin, and the
deposit value must not exceed the coin's denomination value.
\item That the start and end dates for the wire
fee structure are sane, that is cover the timeframe without
overlap or gaps.
\item That denomination signatures on the coins are valid
and match denomination keys known to the auditor.
\item That the target account of the outgoing aggregate wire
transfer is well-formed and matches the account specified
in the deposit.
\item That coins that have been claimed in an aggregation have
a supporting history.
\item That coins which should be aggregated are listed in an
aggregation list, and that the timestamps match the
expected dates.
\end{itemize}
\subsubsection{The \texttt{taler-helper-auditor-coins}}
This helper focuses on checking the history of individual coins (as described
in Figure~\ref{fig:coin:states}), ensuring that the coin is not double-spent
(or over-spent) and that refreshes, refunds and recoups are processed
properly.
Additionally, this tool includes checks for denomination key abuse by
verifying that the value and number of coins deposited in any denomination
does not exceed the value and number of coins issued in that denomination.
Finally, the auditor will also complain if the exchange processes
denominations that it did not properly report (with fee structure) to the
auditor.
The list of invariants checked by this tool thus includes:
\begin{itemize}
\item Testing for an
emergency on denominations because the value or number
of coins deposited exceeds the value or number of coins
issued; if this happens, the exchange should revoke the
respective denomination.
\item Checking for arithmetic inconsistencies from exchanges
not properly calculating balances or fees during the
various coin operations (withdraw, deposit, melt, refund);
\item That signatures are correct for denomination key revocation,
coin denominations,
and coin operations (deposit, melt, refund, recoup)
\item That denomination keys are known to the auditor.
\item That denomination keys were actually revoked if a recoup
is granted.
\item Whether there exists refresh sessions from coins that
have been melted but not (yet) revealed
(this can be harmless and no fault of the exchange, but
could also be indicative of an exchange failing to process
certain requests in a timely fashion).
\item That the refund deadline is not after
the wire deadline (while harmless, such a deposit
makes inconsistent requirements and should have been
rejected by the exchange).
\end{itemize}
\subsubsection{The \texttt{taler-helper-auditor-deposits}}
This tool verifies that the deposit confirmations reported by merchants
directly to the auditor are also included in the database we got from the
exchange. This is to ensure that the exchange cannot defraud merchants by
simply not reporting deposits to the auditor or an
exchange signing key being compromised (as described in
Section~\label{sec:signkey:compromise}).
\subsubsection{The \texttt{taler-helper-auditor-reserves}}
This figure checks the exchange's processing of the
balance of an individual reserve, as described
in Figure~\ref{fig:reserve:states}.
The list of invariants checked by this tool thus includes:
\begin{itemize}
\item Correctness of the signatures that legitimized
withdraw and recoup operations.
\item Correct calculation of the reserve balance given
the history of operations (incoming wire transfers,
withdraws, recoups and closing operations)
involving the reserve.
\item That the exchange closed reserves when required,
and that the exchange wired the funds back to the
correct (originating) wire account.
\item Knowledge of the auditor of the denomination keys
involved in withdraw operations and of the
applicable closing fee.
\item That denomination keys were valid for use in a
withdraw operation at the reported time of withdrawal.
\item That denomination keys were eligible for recoup
at the time of a recoup.
\end{itemize}
\subsubsection{The \texttt{taler-helper-auditor-wire}}
This helper process checks that the incoming and outgoing transfers recorded
in the exchange's database match wire transfers of the underlying bank
account. To access the transaction history (typically recorded by the bank),
the wire auditor helper is special in that it must be provided the necessary
credentials to access the exchange's bank account. In a production setting,
this will typically require the configuration and operation of a Nexus
instance (of LibEuFin) at the auditor.
The actual logic of the wire auditor is pretty boring: it goes over all bank
transactions that are in the exchange's database, and verifies that they are
present in the records from the bank, and then it goes over all bank
transactions reported by the bank, and again checks that they are also in the
exchange's database. This applies for both incoming and outgoing wire
transfers. The tool reports any inconsistencies, be they in terms of wire
transfer subject, bank accounts involved, amount that was transferred, or
timestamp.
For incoming wire transfers, this check protects against the following
failures: An exchange reporting the wrong amount may wrongfully allow or
refuse the withdrawal of coins from a reserve. The wrong wire transfer subject
might allow the wrong wallet to withdraw, and reject the rightful owner. The
wrong bank account could result in the wrong recipient receiving funds if the
reserve is closed. Timestamp differences are usually pretty harmless, and
small differences may even occur due to rounding or clock synchronization
issues. However, they are still reported as they may be indicative of other
problems.
For outgoing wire transfers, the implications arising from an exchange making
the wrong wire transfers should be obvious.
The list of invariants checked by this tool thus includes:
\begin{itemize}
\item The exchange correctly listing all incoming wire transfers.
\item The bank/Nexus having correctly suppressed incoming wire
transfers with non-unique wire transfer subjects, and having
assigned each wire transfer a unique row ID/offset.
\item The exchange correctly listing all outgoing wire transfers
including having the appropriate justifications (aggregation
or reserve closure) for the respective amounts and target accounts.
\item Wire transfers that the exchange has failed to execute that
were due. Note that small delays here can be normal as
wire transfers may be in flight.
\end{itemize}
\subsection{The Auditor's HTTP service}
The auditor exposes a web server with the \texttt{taler-auditor-httpd}
process. Currently, it shows a website that allows the customer to add the
auditor to the list of trusted auditors in their wallet.
It also exposes an endpoint for merchants to submit deposit confirmations.
These merchant-submitted deposit confirmations are checked against the deposit
permissions in the exchange's database to detect compromised signing keys or
missing writes, as described in
Section~\ref{sec:compromised-signing-key-detection}.
In the future, we plan for the auditor to expose additional endpoints where
wallets and merchant backends can submit (cryptographic) proofs of
missbehavior from an exchange. The goal would be to automatically verify the
proofs, take corrective action by including the information in the audit
report and possibly even compensating the victim.
\section{Merchant Backend}
\begin{figure}
\includegraphics[width=\textwidth]{diagrams/taler-diagram-merchant.png}
\caption{Architecture of the merchant reference implementation}
\end{figure}
The Taler merchant backend is a component that abstracts away the details of
processing Taler payments and provides a simple HTTP API. The merchant backend
handles cryptographic operations (signature verification, signing), secret
management and communication with the exchange.
The backend API\footnote{See \url{https://docs.taler.net/api/} for the full documentation}
is divided into two types of HTTP endpoints:
\begin{enumerate}
\item Functionality that is accessed internally by the merchant. These APIs typically
require authentication and/or are only accessible from within the private
network of the merchant.
\item Functionality that is exposed publicly on the Internet and accessed by the customer's wallet and browser.
% FIXME: talk about proxying
\end{enumerate}
A typical merchant has a \emph{storefront} component that customers visit with
their browser, as well as a \emph{back office} component that allows the
merchant to view information about payments that customers made and that integrates
with other components such as order processing and shipping.
\subsection{Processing payments}\label{sec:processing-payments}
To process a payment, the storefront first instructs the backend to create an
\emph{order}. The order contains information relevant to the purchase, and is
in fact a subset of the information contained in the contract terms. The
backend automatically adds missing information to the order details provided by
the storefront. The full contract terms can only be signed once the customer
provides the claim public key for the contract.
Each order is uniquely identified by an order ID, which can be chosen by the
storefront or automatically generated by the backend.
The order ID can be used to query the status of the payment. If the customer
did not pay for an order ID yet, the response from the backend includes a
payment redirect URL. The storefront can redirect the customer to this
payment redirect URL; visiting the URL will trigger the customer's
browser/wallet to prompt for a payment.
To simplify the implementation of the storefront, the merchant backend can
serve a page to the customer's browser that triggers the payment via the HTTP
402 status code and the corresponding headers, and provides a fallback (in the
form of a \texttt{taler:pay} link) for loosely integrated browsers.
When checking the status of a payment that is not settled yet, the response from the merchant backend
will contains a payment redirect URL. The storefront redirects the browser to this URL,
which is served by the merchant backend and triggers the payment.
The code snippet shown in Figure~\ref{fig:merchant-donations-code} implements
the core functionality of a merchant frontend that prompts the customer for a
donation (upon visiting \texttt{/donate} with the right query parameters) and
shows a donation receipt on the fulfillment page with URL \texttt{/receipt}.
The code snippet is written in Python and uses the Flask library\footnote{\url{http://flask.pocoo.org/}} to process HTTP requests.
The helper functions \texttt{backend\_post}
and \texttt{backend\_get} make an HTTP \texttt{POST}/\texttt{GET} request to the merchant backend, respectively,
with the given request body / query parameters.
\begin{figure}
\lstinputlisting[language=Python,basicstyle=\footnotesize]{snippets/donations.py}
\caption[Code snippet for merchant frontend]{Code snippet with core functionality of a merchant frontend to accept donations.}
\label{fig:merchant-donations-code}
\end{figure}
\subsection{Back Office APIs}
The back office API allows the merchant to query information about the history
and status of payments, as well as correlate wire transfers to the merchant's
bank account with the respective GNU Taler payment. This API is necessary to
allow integration with other parts of the merchant's e-commerce infrastructure.
%\subsection{Instances}
%Merchant instances allow one deployment of the merchant backend to host more
%than one logical merchant.
\subsection{Example Merchant Frontends}
We implemented the following applications using the merchant backend API.
\begin{description}
\item[Blog Merchant] The blog merchant's landing page has a list of article titles with a teaser.
When following the link to the article, the customer is asked to pay to view the article.
\item[Donations] The donations frontend allows the customer to select a project to donate to.
The fulfillment page shows a donation receipt.
\item[Codeless Payments] The codeless payment frontend is a prototype for a
user interface that allows merchants to sell products on their website
without having to write code to integrate with the merchant backend.
Instead, the merchant uses a web interface to manage products and their
available stock. The codeless payment frontend then creates an HTML snippet with a payment
button that the merchant can copy-and-paste integrate into their storefront.
\item[Survey] The survey frontend showcases the tipping functionality of GNU Taler.
The user fills out a survey and receives a tip for completing it.
\item[Back office] The example back-office application shows the history and
status of payments processed by the merchant.
\end{description}
The code for these examples is available at \url{https://git.taler.net/} in the
repositories \texttt{blog}, \texttt{donations}, \texttt{codeless}, \texttt{survey}
and \texttt{backoffice} respectively.
\section{Wallet}
\begin{figure}
\includegraphics[width=\textwidth]{diagrams/taler-diagram-wallet.png}
\caption{Architecture of the wallet reference implementation}
\end{figure}
The wallet manages the customer's reserves and coins, lets the customer view
and pay for contracts from merchants. It can be seen in operation in
Section~\ref{sec:intro:ux}.
The reference implementation of the GNU Taler wallet is written in the
TypeScript language against the WebExtension API%
\footnote{\url{https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions}}, a cross-browser mechanism for
browser extensions. The reference wallet is a ``tightly integrated'' wallet, as it directly hooks into
the browser to process responses with the HTTP status code ``402 Payment Required''.
Many cryptographic operations needed to implement the wallet are not commonly
available in a browser environment. We cross-compile the GNU Taler utility
library written in C as well as its dependencies (such as libgcrypt) to asm.js
(and WebAssembly on supported platforms) using the LLVM-based emscripten
toolchain \cite{zakai2011emscripten}.
Cryptographic operations run in an isolated process implemented as a
WebWorker.\footnote{\url{https://html.spec.whatwg.org/}} This design allows
the relatively slow cryptographic operations to run concurrently in the
background in multiple threads. Since the crypto WebWorkers are started on-demand,
the wallet only uses minimal resources when not actively used.
\subsection{Optimizations}\label{sec:wallet-optimizations}
To improve the perceived performance of cryptographic operations,
the wallet optimistically creates signatures in the background
while the user is looking at the ``confirm payment'' dialog. If the user does
not accept the contract, these signatures are thrown away instead of being sent
to the merchant. This effectively hides the latency of the
most expensive cryptographic operations, as they are done while the user
consciously needs to make a decision on whether to proceed with a payment.
\subsection{Coin Selection}
The wallet hides the implementation details of fractionally spending different
denomination from the user, and automatically selects which denominations to
use for withdrawing a given amount, as well as which existing coins to
(partially) spend for a payment.
Denominations for withdrawal are greedily selected, starting with the largest
denomination that fits into the remaining amount to withdraw. Coin selection
for spending proceeds similarly, but first checks if there is a single coin
that can be partially spent to cover the whole amount. After each payment, the
wallet automatically refreshes coins with a remaining amount large enough to be
refreshed. We discuss a simple simulation of the current coin selection algorithm
in Section~\ref{sec:coins-per-transaction}.
A more advanced coin selection would also consider the fee structure of the
exchange, minimizing the number of coins as well as the fees incurred by the
various operations. The wallet could additionally learn typical amounts that
the user spends, and adjust withdrawn denominations accordingly to further
minimize costs. An opposing concern to the financial cost is the anonymity of
customers, which is improved when the spending behavior of wallets is as
similar as possible.
% FIXME: what about anonymity effects of coin selection?
\subsection{Wallet Detection}
When websites such as merchants or banks try to signal the Taler wallet---for example,
to request a payment or trigger reserve creation---it is possible that the
customer simply has no Taler wallet installed. To accommodate for this situation in a
user-friendly way, the HTTP response containing signaling to wallet should
contain as response body an HTML page with (1) a \texttt{taler:} link to
manually open loosely integrated wallets and (2) instructions on how to install
a Taler wallet if the user does not already have one.
It might seem useful to dynamically update page content depending on whether
the Taler wallet is installed, for example, to hide or show a ``Pay with Taler''
or ``Withdraw to Taler wallet'' option. This functionality cannot be provided
in general, as only the definitive presence of a wallet can be detected, but
not its absence when the wallet is only loosely integrated in the user's
browser via a handler for the \texttt{taler:} URI scheme.
We nevertheless consider the ability to know whether a customer has definitely
installed a Taler wallet useful (if only for the user to confirm that the
installation was successful), and expose two APIs to query this. The first one
is JavaScript-based and allows to register a callback for the when
presence/absence of the wallet is detected. The second method works without
any JavaScript on the merchant's page, and uses CSS~\cite{sheets1998level} to dynamically show/hide
element on the page marked with the special \texttt{taler-installed-show} and
\texttt{taler-installed-hide} CSS classes, whose visibility is changed when
a wallet browser extension is loaded.
Browser fingerprinting \cite{mulazzani2013fast} is a concern with any
additional APIs made available to websites, either by the browser itself or by
browser extensions. Since a website can simply try to trigger a payment to
determine whether a tightly integrated Taler wallet is installed, one bit of
additional fingerprinting information is already available through the usage of
Taler. The dynamic detection methods do not, however, expose any information
that is not already available to websites by signaling the wallet through HTTP
headers.
\subsection{Backup and Synchronization}
While users can manually import and export the state of the wallet, at the time
of writing this, automatic backup and synchronization between wallets is not
implemented yet. We discuss the challenges with implementing backup and
synchronization in a privacy-preserving manner in
Chapter~\ref{sec:future-work-backup-sync}.
\subsection{Wallet Liquidation}
If a customer wishes to stop using GNU Taler, they can deposit the remaining
coins in their wallet back to their own bank account. We call this process
\emph{liquidation}.
In deployments with relatively lenient KYC regulation, the normal deposit
functionality used by merchants is used for wallet liquidation. The wallet
simply acts as a merchant for one transaction, and asks the exchange to deposit
the coins into the customer's bank account.
However in deployments with strict KYC regulations, the customer would first
have to register and complete a KYC registration procedure with the exchange.
To avoid this, liquidation can be implemented as a modified deposit, which
restricts the payment to the bank account that was used to create a reserve of
the customer.
The exchange cannot verify that a coin that is being liquidated actually
originated the reserve that the customer claims it originated from, unless the
user reveals the protocol transcripts for withdrawal and refresh operations on
that coin, violating their privacy. Instead, each reserve tracks the amount
that was liquidated into it, and the exchange rejects a liquidation request if
the liquidated amount exceeds the amount that was put into the reserve. Note
that liquidation does not refill the funds of a reserve, but instead triggers a
bank transfer of the liquidated amount to the bank account that
created the reserve.
\subsection{Wallet Signaling}
We now define more precisely the algorithm that the wallet executes when a
website signals to that wallet that an operation related to payments should be
triggered, either by opening a \texttt{taler:pay} URL or by responding
with HTTP 402 and at least one Taler-specific header.
% FIXME: need to specify what happens when gateway_origin="", for example when triggered
% via URL
The steps to process a payment trigger are as follows. The algorithm takes the
following parameters: \texttt{current\_url} (the URL of the page that
raises the 402 status or \texttt{null} if triggered by a \texttt{taler:pay} URL),
\texttt{contract\_url}, \texttt{resource\_url}, \texttt{session\_id},
\texttt{offer\_url}, \texttt{refund\_url}, \texttt{tip\_token} (from the
``Taler-\dots'' headers or \emph{taler:pay} URL parameters respectively)
\begin{enumerate}
\item If \texttt{resource\_url} a non-empty string, set \texttt{target\_url} to \texttt{resource\_url},
otherwise set \texttt{target\_url} to \texttt{current\_url}.
\item If \texttt{target\_url} is empty, stop.
\item If there is an existing payment $p$ whose
fulfillment URL equals \texttt{target\_url} and either \texttt{current\_url} is \texttt{null}
or \texttt{current\_url} has the same origin as
either the fulfillment URL or payment URL in the contract terms, then:
\begin{enumerate}[label*=\arabic*.]
\item If \texttt{session\_id} is non-empty and the last session ID for payment $p$ was recorded
in the wallet with session signature $sig$, construct a fulfillment instance URL from $sig$
and the order ID of $p$.
\item Otherwise, construct an extended fulfillment URL from the order ID of $p$.
\item Navigate to the extended fulfillment URL constructed in the previous step and stop.
\end{enumerate}
\item If \texttt{contract\_url} is a non-empty URL, execute the steps for
processing a contract URL (with \texttt{session\_id}) and stop.
\item If \texttt{offer\_url} is a non-empty URL, navigate to it and stop.
\item If \texttt{refund\_url} is a non-empty URL, process the refund and stop.
\item If \texttt{tip\_url} is a non-empty URL, process the tip and stop.
\end{enumerate}
For interactive web applications that request payments, such as games or single
page apps (SPAs), the payments initiated by navigating to a page with HTTP
status code 402 are not appropriate, since the state of the web application is
destroyed by the navigation. Instead the wallet can offer a JavaScript-based
API, exposed as a single function with a subset of the parameters of the
402-based payment: \texttt{contract\_url}, \texttt{resource\_url},
\texttt{session\_id} \texttt{refund\_url}, \texttt{offer\_url},
\texttt{tip\_token}. Instead of navigating away, the result of the operation
is returned as a JavaScript promise (either a payment receipt, refund
confirmation, tip success status or error). If user input is required (e.g., to
ask for a confirmation for a payment), the page's status must not be destroyed.
Instead, an overlay or separate tab/window displays the prompt to the user.
% FIXME: should be specify the full algorithm for JS payments?
% FIXME talk about clickjacking
\newcommand\inecc{\in \mathbb{Z}_{|\mathbb{E}|}}
\newcommand\inept{\in {\mathbb{E}}}
\newcommand\inrsa{\in \mathbb{Z}_{|\mathrm{dom}(\FDH_K)|}}
\section{Cryptographic Protocols}
\def\HKDF{\textrm{HKDF}}
\def\KDF{\textrm{KDF}}
\def\FDH{\textrm{FDH}}
\newcommand{\iseq}{\stackrel{?}{=}}
\newcommand{\iseqv}{\stackrel{?}{\equiv}}
\newcommand{\pccheck}{\mathbf{check}\ }
In this section, we describe the main cryptographic protocols for Taler in more
detail. The more abstract, high-level protocols from
Section~\ref{sec:crypto:instantiation} are instantiated and and embedded in
concrete protocol diagrams that can hopefully serve as a reference for
implementors.
For ease of presentation, we do not provide a bit-level description of the
cryptographic protocol. Some details from the implementation are left out,
such as fees, additional timestamps in messages and checks for the expiration
of denominations. Furthermore, we do not specify the exact responses in the
error cases, which in the actual implementation should include signatures that
could be used during a legal dispute. Similarly, the actual implementation
contains some additional signatures on messages sent that allow to prove to a
third party that a participant did not follow the protocol.
As we are dealing with financial transactions, we explicitly describe whenever
entities need to safely write data to persistent storage. As long as the data
persists, the protocol can be safely resumed at any step. Persisting data is
cumulative, that is an additional persist operation does not erase the
previously stored information.
The implementation also records additional entries in the exchange's database
that are needed for auditing.
\subsection{Preliminaries}
In our protocol definitions, we write $\mathbf{check}\ \mathrm{COND}$ to abort
the protocol with an error if the condition $\mathrm{COND}$ is false.
We use the following algorithms:
\begin{itemize}
\item $\algo{Ed25519.Keygen}() \mapsto \langle \V{sk}, \V{pk} \rangle$
to generate an Ed25519 key pair.
\item $\algo{Ed25519.GetPub}(\V{sk}) \mapsto \V{pk}$ to derive the public key from
an Ed25519 public key.
\item $\algo{Ed25519.Sign}(\V{sk}, m) \mapsto \sigma$ to create a signature $\sigma$
on message $m$ using secret key $\V{sk}$.
\item $\algo{Ed25519.Verify}(\V{pk}, \sigma, m) \mapsto b$ to check if $\sigma$ is
a valid signature from $\V{pk}$ on message $m$.
\item $\mathrm{HKDF}(n, k, s) \mapsto m$ is the HMAC-based key derivation function \cite{rfc5869},
producing an output $m$ of $n$ bits from the input key material $k$ and salt $s$.
\end{itemize}
We write $\mathbb{Z}^*_N$ for the multiplicative group of integers modulo $N$.
Given an $r \in \mathbb{Z}^*_N$, we write $r^{-1}$ for the multiplicative
inverse modulo $N$ of $r$.
We write $H(m)$ for the SHA-512 hash of a bit string.
We write $\FDH(N,m)$ for the full domain hash that maps the bit string $m$ to
an element of $\mathbb{Z}^*_N$. Specifically, $\FDH(N,m)$ is computed by
first computing $H(m)$. Let $b := \lceil \log_2 N\rceil$. The full domain
hash is then computed by iteratively computing a HKDF to obtain $b$ bits of
output until the $b$-bit value is below $N$. The inputs to the HKDF are a
``secret key'', a fixed context plus a 16-bit counter (in big endian) as a
context chunk that is incremented until the computation succeeds. For the
source key material, we use a binary encoding of the public RSA key with
modulus $N$.\footnote{So technically, it is $\FDH(N,e,m)$, but we use the
simplified notation $\FDH(N,m)$.} Here, the public RSA key is encoded by
first expressing the number of bits of the modulus and the public exponent as
16-bit numbers in big endian, followed by the two numbers (again in unsigned
big endian encoding).\footnote{See
\texttt{GNUNET\_CRYPTO\_rsa\_public\_key\_encode()}.} For the context, the
C-string ``RSA-FDA FTpsW!'' (without 0-termination) is used. For the KDF, we
instantiate the HKDF described in RFC 5869~\cite{rfc5869} using HMAC-SHA512 as
XTR and HMAC-SHA256 as PRF*.\footnote{As suggested in
\url{http://eprint.iacr.org/2010/264.pdf}} Let the result of the first
successful iteration of the HKDF function be $r$ with $0 \le r < N$. Then, to
protect against a malicious exchange when blinding values, the $FDH(N,m)$
function checks that $\gcd(r,n) = 1$. If not, the $\FDH(n,m)$ calculation
fails because $n$ is determined to be malicious.
The expression $x \randsel X$ denotes uniform random selection of an element
$x$ from set $X$. We use $\algo{SelectSeeded}(s, X) \mapsto x$ for pseudo-random uniform
selection of an element $x$ from set $X$ and seed $s$. Here, the result is deterministic for fixed inputs $s$ and $X$.
The exchange's denomination signing key pairs $\{\langle \V{skD}_i, \V{pkD}_i \rangle \}$ are RSA keys pairs,
and thus $\V{pkD}_i = \langle e_i, N_i \rangle$, $\V{skD_i} = d_i$. We write $D(\V{pkD}_i)$ for the
financial value of the denomination $\V{pkD}_i$.
% FIXME: explain RSA keys of exchange
\subsection{Withdrawing}
The withdrawal protocol is defined in Figure~\ref{fig:withdraw-protocol}.
The following additional algorithms are used, which we only define informally here:
\begin{itemize}
\item $\algo{CreateBalance}(W_p, v) \mapsto \bot$ is used by the exchange,
and has the side-effect of creating a reserve record with balance $v$
and reserve public key (effectively the identifier of the reserve) $W_p$.
\item $\algo{GetWithdrawR}(\rho) \mapsto \{\bot,\overline{\sigma}_C\}$
is used by the exchange, and checks
if there is an existing withdraw request $\rho$. If the existing request
exists, the existing blind signature $\overline{\sigma}_C$ over
coin $C$ is returned. On a fresh request, $\bot$ is
returned.
\item $\algo{BalanceSufficient}(W_s,\V{pkD}_t) \mapsto b$ is used by the exchange, and
returns true if the balance in the reserve identified by $W_s$ is sufficient to
withdraw at least one coin if denomination $\V{pkD}_t$.
\item $\algo{DecreaseBalance}(W_s,\V{pkD}_t) \mapsto \bot$ is used by the exchange, and
decreases the amount left in the reserve identified by $W_s$ by the amount $D(\V{pkD}_t)$
that the denomination $\V{pkD}_t$ represents.
\end{itemize}
\begin{figure}
\centering
\fbox{%
\pseudocode[codesize=\small]{%
\textbf{Customer} \< \< \textbf{Exchange} \\
\text{Knows } \{ \langle e_i,N_i \rangle \} = \{\V{pkD}_i\} \< \< \text{Knows } \{ \langle \V{skD}_i, \V{pkD}_i \rangle \} \pclb
\pcintertext[dotted]{Create Reserve}
\langle w_s, W_p \rangle \leftarrow \algo{Ed25519.Keygen}() \< \< \\
\text{Persist reserve } \langle w_s,v \rangle \< \< \\
\< \sendmessageright{top={Bank transfer}, bottom={(subject: $W_p$, amount: $v$)},style=dashed} \< \\
\< \< \algo{CreateBalance}(W_p, v) \pclb
\pcintertext[dotted]{Prepare Withdraw}
\text{Choose $t$ with $\V{pkD}_t \in \{\V{pkD}_i\}$} \< \< \\
\langle c_s, C_p \rangle \leftarrow \algo{Ed25519.Keygen}() \< \< \\
r \randsel \mathbb{Z}^*_N \< \< \\
\text{Persist planchet } \langle c_s, r \rangle \< \< \pclb
\pcintertext[dotted]{Execute Withdraw}
\overline{m} := \FDH(N_t, C_p) \cdot r^{e_t} \bmod N_t \< \< \\
\rho_W := \langle \V{pkD}_t, \overline{m} \rangle \< \< \\
\sigma_W := \algo{Ed25519.Sign}(w_s, \rho_W) \< \< \\
\< \sendmessageright*{\rho := \langle W_p, \sigma_W, \rho_W \rangle} \< \\
\< \< \pccheck \V{pkD}_t \in \{ \V{pkD}_i \} \\
\< \< \pccheck \algo{Ed25519.Verify}(W_p,\rho_W,\sigma_W) \\
\< \< x \leftarrow \algo{GetWithdraw}(\rho) \\
\< \< \pcif x \iseq \bot \\
\< \< \t \pccheck \algo{BalanceSufficient}(W_p,\V{pkD}_t) \\
\< \< \t \algo{DecreaseBalance}(W_p, \V{pkD}_t) \\
\< \< \t \text{Persist withdrawal $\rho$} \\
\< \< \t \overline{\sigma}_C := (\overline{m})^{\V{skD}_t} \bmod N_t \\
\< \< \pcelse \\
\< \< \t \overline{\sigma}_C := x \\
\< \sendmessageleft*{\overline{\sigma}_C} \< \\
\sigma_C := r^{-1}\overline{\sigma}_C \< \< \\
\pccheck \sigma_C^{e_t} \iseqv_{N_t} \FDH(N_t, C_p) \< \< \\
\text{Persist coin $\langle \V{pkD}_t, c_s, C_p, \sigma_C \rangle$} \< \< \\
}
}
\caption[Withdraw protocol diagram.]{Withdrawal protocol diagram.}
\label{fig:withdraw-protocol}
\end{figure}
\subsection{Payment transactions}
The payment protocol is defined in two parts. First, the spend protocol in
Figure~\ref{fig:payment-spend} defines the interaction between a merchant and
a customer. The customer obtains the contract terms (as $\rho_P$) from the
merchant, and sends the merchant deposit permissions as a payment. The deposit protocol
in Figure~\ref{fig:payment-deposit} defines how subsequently the merchant sends the
deposit permissions to the exchange to detect double-spending and ultimately
to receive a bank transfer from the exchange.
Note that in practice the customer can also execute the deposit
protocol on behalf of the merchant. This is useful in situations where
the customer has network connectivity but the merchant does not. It
also allows the customer to complete a payment before the payment
deadline if a merchant unexpectedly becomes unresponsive, allowing the
customer to later prove that they paid on time.
We limit the description to one exchange here, but in practice, the merchant
communicates to the customer the exchanges that it supports, in addition to the
account information $A_M$ that might differ between exchanges.
We use the following algorithms, defined informally here:
\begin{itemize}
\item $\algo{SelectPayCoins}(v, E_M) \mapsto \{ \langle \V{coin}_i, f_i \rangle \}$ selects
fresh coins (signed with denomination keys from exchange $E_M$)
to pay for the amount $v$. The result is a set of coins
together with the fraction of each coin that must be spent such that
the amounts contributed by all coins sum up to $v$.
\item $\algo{MarkDirty}(\V{coin}, f) \mapsto \bot$ subtracts the fraction $f$ from the
available amount left on a coin, and marks the coin as dirty (to trigger refreshing
in case $f$ is below the denomination value). Thus, assuming the coin has
any residual value, the customer's wallet will do a refresh on $\V{coin}$
and not use it for further payments. This provides unlinkability of transactions
made with change arising from paying with fractions of a coin's denomination.
\item $\algo{Deposit}(E_M, D_i) \mapsto b$ executes the second part of the payment protocol
(i.e., the deposit) with exchange $E_M$, using deposit permission $D_i$.
\item $\algo{GetDeposit}(C_p, h) \mapsto \{\bot,\rho_{(D,i)}\}$ checks in the exchange's database
for an existing processed deposit permission on coin $C_p$ for the contract
identified by $h$. The algorithm returns the existing deposit permission $\rho_{(D,i)}$, or $\bot$ if a
matching deposit permission is not recorded.
\item $\algo{IsOverspending}(C_p, \V{pkD}, f) \mapsto b$ checks in the exchange's database
if there if at least the fraction $f$ of the coin $C_p$ of denomination $\V{pkD}$ is still available
for use, based on existing spend/withdraw records of the exchange.
\item $\algo{MarkFractionalSpend}(C_p, f) \mapsto \bot$ adds a spending
record to the exchanges database, indicating
that fraction $f$ of coin $C_p$ has been spent (in addition to
existing spending/refreshing records).
\item $\algo{ScheduleBankTransfer}(A_M, f, \V{pkD}, h_c) \mapsto \bot$
schedules a bank transfer from the exchange to
the account identified by $A_M$, for subject $h_c$ and for the amount $f\cdot D(\V{pkD})$.
% NOTE: actual implementation avoids multiplication (messy!) and would
% simply require f \le D(\V{pkD})!
\end{itemize}
\begin{figure}
\centering
\fbox{%
\pseudocode[codesize=\footnotesize]{%
\textbf{Customer} \< \< \textbf{Merchant} \\
\text{Knows } \V{pkM} \< \< \text{Knows } \langle \V{pkM}, \V{skM} \rangle \\
\< \sendmessageright{top={Select product/service},style=dashed} \< \\
\< \< \text{Determine:} \\
\< \< \text{$\bullet$ } v \text{ (price) } \\
\< \< \text{$\bullet$ } E_M \text{ (exchange) } \\
\< \< \text{$\bullet$ } A_M \text{ (acct.) } \\
\< \< \text{$\bullet$ } \V{info} \text{ (free-form details) } \\
\< \sendmessageleft{top={Request payment},style=dashed} \< \\
\langle p_s, P_p \rangle \leftarrow \algo{Ed25519.Keygen}() \< \< \\
\text{Persist ownership identifier } p_s \< \< \\
\< \sendmessageright*{P_p} \< \\
\< \< \rho_P := \langle E_M, A_M, \V{pkM}, H(\langle v, \V{info}\rangle), P_p \rangle \\
\< \< \sigma_P := \V{Ed25519.Sign}(\V{skM}, \rho_P) \\
\< \sendmessageleft*{\rho_P, \sigma_P, v, \V{info}} \< \\
\langle M, A_M, \V{pkM}, h', P_p' \rangle := \rho_P \< \< \\
\pccheck \algo{Ed25519.Verify}(pkM, \sigma_P, \rho_P) \< \< \\
\pccheck P_p' \iseq P_p \< \< \\
\pccheck h' \iseq H(\langle v, \V{info} \rangle ) \< \< \\
\V{cf} \leftarrow \algo{SelectPayCoins}(v, E_M) \< \< \\
\pcfor \langle \V{coin_i,f_i} \rangle \in \V{cf} \< \< \\
\t \algo{MarkDirty}(\V{coin}_i, f_i) \< \< \\
\t \langle c_s, C_p, \V{pkD}, \sigma_C \rangle := \V{coin}_i \< \< \\
\t \rho_{(D,i)} := \langle C_p, \V{pkD}, \sigma_C, f_i, H(\rho_P), A_M, \V{pkM} \rangle \< \< \\
\t \sigma_{(D,i)} := \V{Ed25519.Sign}(c_s, \rho_{(D,i)}) \< \< \\
\text{Persist } \langle \sigma_P, \V{cf}, \rho_P, \rho_{(D,i)}, \sigma_{(D,i)}, v, \V{info} \rangle \< \<\\
\< \sendmessageright*{ \mathcal{D} := \{\langle \rho_{(D,i)}, \sigma_{(D,i)}\rangle \}} \< \\
\< \< \pcfor D_i \in \mathcal{D} \\
\< \< \t \pccheck \algo{Deposit}(E_M, D_i) \\
}
}
\caption[Spend protocol diagram.]{Spend Protocol executed between customer and merchant for the purchase
of an article of price $v$ using coins from exchange $E_M$. The merchant has
provided his account details to the exchange under an identifier $A_M$.
The customer can identify themselves as the one who received the offer
using $p_s$.
%This prevents multiple customers from legitimately paying for the
%same article and potentially exhausting stocks.
}
\label{fig:payment-spend}
\end{figure}
\begin{figure}
\centering
\fbox{%
\pseudocode[codesize=\small]{%
\textbf{Customer/Merchant} \< \< \textbf{Exchange} \\
\text{Knows } \V{pkESig} \< \< \text{Knows } \V{skESig}, \V{pkESig}, \{ \V{pkD}_i \} \\
\text{Knows } D_i = \langle \rho_{(D,i)}, \sigma_{(D,i)} \rangle \< \< \\
\< \sendmessageright*{ D_i } \< \\
\< \< \langle \rho_{(D,i)}, \sigma_{(D,i)} \rangle := D_i \\
\< \< \langle C_p, \V{pkD}, \sigma_C, f_i, h, A_M, \V{pkM} \rangle := \rho_{(D,i)} \\
\< \< \pccheck \V{pkD} \in \{ \V{pkD}_i \} \\
\< \< \langle e, N \rangle := \V{pkD} \\
\< \< \pccheck \algo{Ed25519.Verify}(C_p, \sigma_{(D,i)}, \rho_{(D,i)}) \\
\< \< x \leftarrow \algo{GetDeposit}(C_p, h) \\
\< \< \pcif x \iseq \bot \\
\< \< \t \pccheck \sigma_C^{e} \iseqv_N \FDH(N, C_p) \\
\< \< \t \pccheck \neg\algo{IsOverspending}(C_p, \V{pkD}, f) \\
\< \< \t \text{Persist deposit-record } D_i \\
\< \< \t \algo{MarkFractionalSpend}(C_p, f) \\
\< \< \t \algo{ScheduleBankTransfer}(A_M, f, \V{pkD}, h_c) \\
\< \< \pcelse \\
\< \< \t \pccheck x \iseq \rho_{(D,i)} \\
\< \< \sigma_{DC} \leftarrow \algo{Ed25519.Sign}(\V{pkESig}, \rho_{(D,i)}) \\
\< \sendmessageleft*{ \sigma_{DC} } \< \\
\pccheck \algo{Ed25519.Verify} \\{}\qquad(\V{pkESig}, \sigma_{DC}, \rho_{(D,i)}) \< \< \\
}
}
\caption[Deposit protocol diagram.]{Deposit Protocol run for each deposited coin $D_i \in {\cal D}$ with the
exchange that signed the coin.}
\label{fig:payment-deposit}
\end{figure}
\subsection{Refreshing and Linking}
The refresh protocol is defined in Figures~\ref{fig:refresh-part1} and
\ref{fig:refresh-part2}. The refresh protocol allows the customer to
obtain change for the remaining fraction of the value of a coin. The
change is generated as a fresh coin that is unlinkable to the dirty
coin to anyone except for the owner of the dirty coin.
A na\"ive implementation of a refresh protocol that just gives the customer a
new coin could be used for peer-to-peer transactions that hides income from tax
authorities. Thus, (with probability $(1-1/\kappa)$) the refresh protocol
records information that allows the owner of the original coin to obtain the
refreshed coin from the original coin via the linking protocol (illustrated in
Figure~\ref{fig:link}).
We use the following algorithms, defined informally here:
\begin{itemize}
\item \algo{RefreshDerive} is defined in Figure~\ref{fig:refresh-derive}.
\item $\algo{GetOldRefresh}(\rho_{RC}) \mapsto \{\bot,\gamma\}$ returns the past
choice of $\gamma$ if $\rho_{RC}$ is a refresh commit message that has been seen before,
and $\bot$ otherwise.
\item $\algo{IsConsistentChallenge}(\rho_{RC}, \gamma) \mapsto \{ \bot,\top \}$ returns
$\top$ if no refresh-challenge has been persisted for the refresh operation by commitment
$\rho_{RC}$ or $\gamma$ is consistent with the persisted (and thus previously received) challenge;
returns $\bot$ otherwise.
\item $\algo{LookupLink}(C_p) \mapsto \{ \langle \rho_{L}^{(i)}, \sigma_L^{(i)},
\overline{\sigma}_C^{(i)} \rangle \}$ looks up refresh records on coin with public key $C_p$ in
the exchange's database and returns the linking message $\rho_L^{(i)}$, linking
signature $\sigma_L^{(i)}$ and blinded signature $\overline{\sigma}_C^{(i)}$ for each refresh
record $i$.
\end{itemize}
\begin{figure}
\centering
\fbox{%
\procedure[codesize=\small]{$\algo{RefreshDerive}(s, \langle e, N \rangle, C_p)$}{%
t := \HKDF(256, s, \texttt{"t"}) \\
T := \algo{Curve25519.GetPub}(t) \\
x := \textrm{ECDH-EC}(t, C_p) \\
r := \algo{SelectSeeded}(x, \mathbb{Z}^*_{N}) \\
c_s := \HKDF(256, x, \texttt{"c"}) \\
C_p := \algo{Ed25519.GetPub}(c_s) \\
\overline{m} := r^{e}\cdot C_p \mod N \\
\pcreturn \langle t, T, x, c_s, C_p, \overline{m} \rangle
}
}
\caption[RefreshDerive algorithm]{The RefreshDerive algorithm running with the seed $s$ on dirty coin $C_p$ to
generate a fresh coin to be later signed with denomination key $pkD := \langle e,N\rangle$.}
\label{fig:refresh-derive}
\end{figure}
\begin{figure}
\centerline{
\fbox{%
\pseudocode[codesize=\footnotesize]{%
\textbf{Customer} \< \< \textbf{Exchange} \\
\text{Knows } \{ \V{pkD}_i \} \< \< \text{Knows } \{\langle \V{skD}_i, \V{pkD}_i \rangle \} \\
\text{Knows } \V{coin}_0 = \langle \V{pkD}_0, c_s^{(0)}, C_p^{(0)}, \sigma_{C}^{(0)} \rangle \< \< \\
\text{Select } \langle N_t, e_t \rangle := \V{pkD}_t \in \{ \V{pkD}_i \} \< \< \\
\pcfor i = 1,\dots,\kappa \< \< \\
\t s_i \randsel \{0,1\}^{256} \< \< \\
\t X_i := \algo{RefreshDerive}(s_i, \V{pkD}_t, C_p^{(0)}) \< \< \\
\t (t_i, T_i, x_i, c_s^{(i)}, C_p^{(i)}, \overline{m}_i) := X_i \< \< \\
h_T := H(T_1,\dots,T_\kappa) \< \< \\
h_{\overline{m}} := H(\overline{m}_1,\dots,\overline{m}_\kappa) \< \< \\
h_C := H(h_t, h_{\overline{m}}) \< \< \\
\rho_{RC} := \langle h_C, \V{pkD}_t, \V{pkD}_0, C_p^{(0)}, \sigma_{C}^{(0)} \rangle \< \< \\
\sigma_{RC} := \algo{Ed25519.Sign}(c_s^{(0)}, \rho_{RC}) \< \< \\
\text{Persist refresh-request } \langle \rho_{RC}, \sigma_{RC} \rangle \< \< \\
\< \sendmessageright*{ \rho_{RC}, \sigma_{RC} } \< \\
\< \< (h_C, \V{pkD}_t, \V{pkD}_0, C_p^{(0)}, \sigma_{C}^{(0)}) := \rho_{RC} \\
\< \< \pccheck \algo{Ed25519.Verify}(C_p^{(0)}, \sigma_{RC}, \rho_{RC}) \\
\< \< x \leftarrow \algo{GetOldRefresh}(\rho_{RC}) \\
\< \< \pcif x \iseq \bot \\
\< \< \t v := D(\V{pkD}_t) \\
\< \< \t \langle e_0, N_0 \rangle := \V{pkD}_0 \\
\< \< \t \pccheck \neg\algo{IsOverspending}(C_p^{(0)}, \V{pkD}_0, v) \\
\< \< \t \pccheck \V{pkD}_t \in \{ \V{pkD}_i \} \\
\< \< \t \pccheck \FDH(N_0, C_p^{(0)}) \iseqv_{N_0} (\sigma_0^{(0)})^{e_0} \\
\< \< \t \algo{MarkFractionalSpend}(C_p^{(0)}, v) \\
\< \< \t \gamma \randsel \{1,\dots,\kappa\} \\
\< \< \t \text{Persist refresh-record } \langle \rho_{RC},\gamma \rangle \\
\< \< \pcelse \\
\< \< \t \gamma := x \\
\< \sendmessageleft*{ \gamma } \< \pclb
\pcintertext[dotted]{(Continued in Figure~\ref{fig:refresh-part2})}
}}}
\caption{Refresh Protocol (Commit Phase)}
\label{fig:refresh-part1}
\end{figure}
\begin{figure}
\centerline{
\fbox{%
\pseudocode[codesize=\footnotesize]{%
\textbf{Customer} \< \< \textbf{Exchange} \pclb
\pcintertext[dotted]{(Continuation of \ref{fig:refresh-part1})} \\
\< \sendmessageleft*{ \gamma } \< \\
\pccheck \algo{IsConsistentChallenge}(\rho_{RC}, \gamma) \< \< \\
\text{Persist refresh-challenge $\langle \rho_{RC}, \gamma \rangle$} \< \< \\
S := \langle s_1,\dots,s_{\gamma-1},s_{\gamma+1},\dots,s_\kappa \rangle \< \< \\
\rho_{L} = \langle C_p^{(0)}, \V{pkD}_t, T_\gamma, \overline{m}_\gamma \rangle \< \< \\
\rho_{RR} = \langle T_\gamma, \overline{m}_\gamma, S \rangle \< \< \\
\sigma_{L} = \algo{Ed25519.Sign}(c_s^{(0)}, \rho_{L}) \< \< \\
\< \sendmessageright*{ \rho_{RR}, \rho_{L}, \sigma_{L} } \< \\
\< \< \langle T'_\gamma, \overline{m}'_\gamma, S \rangle := \rho_{RR} \\
\< \< \langle s_1,\dots,s_{\gamma-1},s_{\gamma+1},\dots,s_\kappa \rangle ) := S \\
\< \< \pccheck \algo{Ed25519.Verify}(C_p^{(0)}, \sigma_L, \rho_L) \\
\< \< \pcfor i = 1,\dots,\gamma-1,\gamma+1,\dots,\kappa \\
\< \< \t X_i := \algo{RefreshDerive}(s_i, \V{pkD}_t, C_p^{(0)}) \\
\< \< \t \langle t_i, T_i, x_i, c_s^{(i)}, C_p^{(i)}, \overline{m}_i \rangle := X_i \\
\< \< h_T' = H(T_1,\dots,T_{\gamma-1},T'_{\gamma},T_{\gamma+1},\dots,T_\kappa) \\
\< \< h_{\overline{m}}' = H(\overline{m}_1,\dots,\overline{m}_{\gamma-1},\overline{m}'_{\gamma},\overline{m}_{\gamma+1},\dots,\overline{m}_\kappa) \\
\< \< h_C' = H(h_T', h_{\overline{m}}') \\
\< \< \pccheck h_C \iseq h_C' \\
\< \< \overline{\sigma}_C^{(\gamma)} := \overline{m}^{skD_t} \\
\< \sendmessageleft*{\overline{\sigma}_C^{(\gamma)}} \< \\
\sigma_C^{(\gamma)} := r^{-1}\overline{\sigma}_C^{(\gamma)} \< \< \\
\pccheck (\sigma_C^{(\gamma)})^{e_t} \iseqv_{N_t} C_p^{(\gamma)} \< \< \\
\text{Persist coin $\langle \V{pkD}_t, c_s^{(\gamma)}, C_p^{(\gamma)}, \sigma_C^{(\gamma)} \rangle$} \< \< \\
}}}
\caption{Refresh Protocol (Reveal Phase)}
\label{fig:refresh-part2}
\end{figure}
\begin{figure}
\centering
\fbox{%
\pseudocode[codesize=\footnotesize]{%
\textbf{Customer} \< \< \textbf{Exchange} \\
\text{Knows } \V{coin}_0 = \langle \V{pkD}_0, c_s^{(0)}, C_p^{(0)}, \sigma_{C}^{(0)} \rangle \< \< \\
\< \sendmessageright*{C_p^{(0)}} \< \\
\< \< L := \algo{LookupLink}(C_p^{(0)}) \\
\< \sendmessageleft*{L} \< \\
\pcfor \langle \rho_{L}^{(i)}, \overline{\sigma}_L^{(i)}, \sigma_C^{(i)} \rangle \in L \< \< \\
\t \langle \hat{C}_p^{(i)}, \V{pkD}_t^{(i)}, T_\gamma^{(i)}, \overline{m}_\gamma^{(i)} \rangle := \rho_L^{(i)} \< \< \\
\t \langle e_t^{(i)}, N_t^{(i)} \rangle := \V{pkD}_t^{(i)} \< \< \\
\t \pccheck \hat{C}_p^{(i)} \iseq C_p^{(0)} \< \< \\
\t \pccheck \algo{Ed25519.Verify}(C_p^{(0)}, \rho_{L}^{(i)}, \sigma_L^{(i)})\< \< \\
\t x_i := \algo{ECDH}(c_s^{(0)}, T_\gamma^{(i)}) \< \< \\
\t r_i := \algo{SelectSeeded}(x_i, \mathbb{Z}^*_{N_t}) \\
\t c_s^{(i)} := \HKDF(256, x_i, \texttt{"c"}) \\
\t C_p^{(i)} := \algo{Ed25519.GetPub}(c_s^{(i)}) \\
\t \sigma_C^{(i)} := (r_i)^{-1} \cdot \overline{m}_\gamma^{(i)} \\
\t \pccheck (\sigma_C^{(i)})^{e_t^{(i)}} \iseqv_{N_t^{(i)}} C_p^{(i)} \\
\t \text{(Re-)obtain coin } \langle \V{pkD}_t^{(i)}, c_s^{(i)}, C_p^{(i)}, \sigma_C^{(i)} \rangle
}
}
\caption{Linking protocol}
\label{fig:link}
\end{figure}
\clearpage
\subsection{Refunds}
The refund protocol is defined in Figure~\ref{fig:refund}. The customer
requests from the merchant that a deposit should be ``reversed'', and if the
merchants allows the refund, it authorizes the exchange to apply the refund and
sends the refund confirmation back to the customer. Note that in practice,
refunds are only possible before the refund deadline, which is not considered
here.
We use the following algorithms, defined informally here:
\begin{itemize}
\item $\algo{ShouldRefund}(\rho_P, m) \mapsto \{ \top, \bot \}$ is used by the merchant to
check whether a refund with reason $m$ should be given for the purchase identified by the
contract terms $\rho_P$. The decision is made according to the merchant's business rules.
\item $\algo{LookupDeposits}(\rho_P, m) \mapsto \{ \langle \rho_{(D,i)},
\sigma_{(D,i)} \rangle \}$ is used by the merchant to retrieve deposit
permissions that were previously sent by the customer and already deposited
with the exchange.
\item $\algo{RefundDeposit}(C_p, h, f, \V{pkM})$ is used by the exchange to
modify its database. It (partially) reverses the amount $f$ of a deposit
of coin $C_p$ to the merchant $\V{pkM}$ for the contract identified by $h$.
The procedure is idempotent, and subsequent invocations with a larger $f$
increase the refund.
\end{itemize}
\begin{figure}
\centerline{
\fbox{%
\pseudocode[codesize=\footnotesize]{%
\< \< \pclb
\pcintertext[dotted]{Request refund} \\
\textbf{Customer} \< \< \textbf{Merchant} \\
\text{Knows } \V{pkM}, \V{pkESig} \< \< \text{Knows } \langle \V{pkM}, \V{skM} \rangle, \V{pkESig} \\
\< \sendmessageright{top={Ask for refund},bottom={(Payment $\rho_P$, reason $m$)},style=dashed} \< \\
\< \< \pccheck \algo{ShouldRefund}(\rho_P,m) \pclb
\pcintertext[dotted]{Execute refund} \\
\textbf{Exchange} \< \< \textbf{Merchant} \\
\text{Knows } \langle \V{skESig}, \V{pkESig} \rangle \< \< \\
\< \< \pcfor \langle \rho_{(D,i)}, \cdot \rangle \in \algo{LookupDeposits}(\rho_P) \\
\< \< \t \rho_{(X,i)} := \langle \mathtt{"refund"}, \rho_D \rangle \\
\< \< \t \sigma_{(X,i)} := \algo{Ed25519.Sign}(\V{skM}, \rho_{(X,i)}) \\
\< \sendmessageleft*{X := \{ \rho_{(X,i)}, \sigma_{(X,i)} \} } \< \\
\pcfor \langle \rho_{(X,i)}, \sigma_{(X,i)} \rangle \in X \< \< \\
\t \pccheck \langle \mathtt{"refund"}, \rho_D \rangle := \rho_X \< \< \\
\t \pccheck \langle C_p, \V{pkD}, \sigma_C, f, h, A_M, \V{pkM} \rangle := \rho_D \\
\t \pccheck \algo{Ed25519.Verify}(\V{pkM}, \rho_X, \sigma_X) \< \< \\
\t \algo{RefundDeposit}(C_p, h, f, \V{pkM}) \< \< \\
\t \rho_{(XC,i)} := \langle \mathtt{"refunded"}, \rho_D \rangle \< \< \\
\t \sigma_{(XC,i)} := \algo{Ed25519.Sign}(\V{skESig}, \rho_{(XC,i)}) \< \< \\
\< \sendmessageright*{XC := \{ \rho_{(XC,i)}, \sigma_{(XC,i)} \} } \< \pclb
\pcintertext[dotted]{Confirm refund} \\
\textbf{Customer} \< \< \textbf{Merchant} \\
\< \sendmessageleft*{XC} \< \\
\pcfor \langle \rho_{(XC,i)}, \sigma_{(XC,i)} \rangle \in XC \< \< \\
\t \pccheck \algo{Ed25519.Verify}(\V{pkESig}, \rho_{(XC,i)}, \sigma_{(XC,i)}) \< \< \\
}
}
}
\caption{Refund protocol}
\label{fig:refund}
\end{figure}
\clearpage
\section{Experimental results}
We now evaluate the performance of the core components of the reference
implementation of GNU Taler. No separate benchmarks are provided for the
merchant backend, as the work done by the merchant per transaction is
relatively negligible compared to the work done by the exchange, and one exchange needs
to provide service many merchants and all of their customers. Thus, the exchange
is the bottleneck for the performance of the system.
We provide a microbenchmark for the performance of cryptographic operations in
the wallet (Table~\ref{table:wallet-benchmark}. Even on a low-end smartphone
device, the most expensive cryptographic operations remain well under
$150ms$, a threshold for user-interface latency under which user happiness and
productivity is considered to be unaffected \cite{tolia2006quantifying}.
\begin{table}
\centering
\begin{subtable}[t]{0.4\linewidth}
\centering{
\begin{tabular}{lr}
\toprule
Operation & Time (ms) \\
\midrule
eddsa create & 9.69 \\
eddsa sign & 22.31 \\
eddsa verify & 19.28 \\
hash big & 0.05 \\
hash small & 0.13 \\
rsa 2048 blind & 3.35 \\
rsa 2048 unblind & 4.94 \\
rsa 2048 verify & 1.97 \\
rsa 4096 blind & 10.38 \\
rsa 4096 unblind & 16.13 \\
rsa 4096 verify & 6.57 \\
\bottomrule
\end{tabular}}
\caption{Wallet microbenchmark on a Laptop (Intel i7-4600U) with Firefox}
\end{subtable}
\qquad
\begin{subtable}[t]{0.4\linewidth}
\centering{
\begin{tabular}{lr}
\toprule
Operation & Time (ms) \\
\midrule
eddsa create & 34.80 \\
eddsa sign & 78.55 \\
eddsa verify & 72.50 \\
hash big & 0.51 \\
hash small & 1.37 \\
rsa 2048 blind & 14.35 \\
rsa 2048 unblind & 19.78 \\
rsa 2048 verify & 9.10 \\
rsa 4096 blind & 47.86 \\
rsa 4096 unblind & 69.91 \\
rsa 4096 verify & 29.02 \\
\bottomrule
\end{tabular}}
\caption{Wallet microbenchmark on Android Moto G3 with Firefox}
\end{subtable}
\caption{Wallet microbenchmarks}
\label{table:wallet-benchmark}
\end{table}
We implemented a benchmarking tool that starts a single (multi-threaded)
exchange and a bank process for the taler-test wire transfer protocol. It then
generates workload on the exchange with a configurable number of concurrent
clients and operations. The benchmarking tool is able to run the exchange on a
different machine (via SSH\footnote{\url{https://www.openssh.com/}}) than the benchmark driver, mock bank and clients.
At the end, the benchmark outputs the number of deposited coins per second and
latency statistics.
\subsection{Hardware Setup}
We used two server machines (\texttt{firefly} and \texttt{gv}) with the following
hardware specifications for our tests:
\begin{itemize}
\item \texttt{firefly} has a 96-core AMD EPYC 7451 CPU and 256GiB DDR4\@2667 MHz RAM.
\item \texttt{gv} has a 16-core Intel(R) Xeon X5550 (2.67GHz) CPU and 128GiB DDR3\@1333 MHz RAM.
\end{itemize}
We used $2048$-bit RSA denomination keys for all of our exchange benchmarks. We
used a development version of the exchange (with git commit hash
5fbda29b76c24d\dots). PostgreSQL version 11.3 was used as the database.
As our server machines have only slower hard-disk drives instead of faster solid-state drives,
we ran the benchmarks with an in-memory database.
\subsection{Coins Per Transaction}\label{sec:coins-per-transaction}
The transaction rate is an important characteristic of a payment system. Since
GNU Taler internally operates on the level of coins instead of transactions, we
need to define what actually consititutes one transaction in our measurements.
This includes both how many coins are used per transaction on average, as well
as how often refresh operations are run.
We ran a simple simulation to determine rather conservative upper bounds for
the parameters that characterize the average transaction.
In the simulation, thirteen denominations of values $2^0,\dots,2^{12}$ are
available. Customers repeatedly select a random value to be spent between $4$ and $5000$.
When customers do not have enough coins for a transaction, they withdraw a
uniform random amount between the minimum amount to complete the transaction
and $10000$. The denominations selected for withdrawal are chosen by greedy
selection of the largest possible denomination. When spending, the customer
first tries to use one coin, namely the smallest coin larger than the
requested amount. If no such coin exists in the customer's wallet, the
customer pays with multiple coins, spending smallest coins first.
Choosing a random uniform amount for withdrawal could be considered
unrealistic, as customers in practice likely would select from a fixed list of
common withdrawal amounts, just like most ATMs operate.
Thus, we also implemented a variation of the simulation that withdraws a constant
amount of $1250$ (i.e., $1/4$ of the maximum transaction value) if it is sufficient
for the transaction, and the exact required amount otherwise.
We obtained the following results for the number of average operations
executed for one ``business transaction'':
\begin{table}[H]
\centering
\begin{tabular}{lSS}
\toprule
& {random withdraw} & {constant withdraw} \\
\midrule
\#spend operations & 8.3 & 7.0 \\
\#refresh operations & 1.3 & 0.51 \\
\#refresh output coins & 4.2 & 3.62 \\
\bottomrule
\end{tabular}
\end{table}
Based on these results, we chose the parameters for our benchmark: for every
spend operation we run a refresh operation with probability $1/10$, where each
refresh operation produces $4$ output coins. In order to arrive at the
transaction rate, the rate of spend operations should be divided by $10$.
Note that this is a rather conservative analysis. In practice, the coin
selection for withdrawal/spending can use more sophisticated optimization
algorithms, rather than using greedy selection. Furthermore, we expect that the
amounts paid in real-world transactions will have more predictable
distributions, and thus the offered denominations can be adjusted to typical
amounts.
\subsubsection{Baseline Sequential Resource Usage}
To obtain a baseline for the resource usage of the exchange, we ran the benchmark on
\texttt{firefly} with a single client that executes sequential requests to
withdraw and spend $10000$ coins, with $10\%$ refresh probability.
% FIXME: talk about TFO, compression and keep-alive
Table~\ref{table:benchmark:ops-baseline} shows the time used for cryptographic
operations, together with the number of times they are executed by the clients
(plus the mock bank and benchmark setup) and exchange, respectively. Note that
while we measured the wall-clock time for these operations, the averages should
correspond to the actual CPU time required for the respective operations, as
the benchmark with one client runs significantly fewer processes/threads than
the number of available CPUs on our machine.
The benchmark completed in $15.10$ minutes on $\texttt{firefly}$. We obtained the total CPU usage of
the benchmark testbed and exchange. The refresh operations are rather slow in comparison
to spends and deposits, as the benchmark with a refresh probability of $0\%$ only took $8.84$
minutes to complete.
\begin{table}
\centering
\begin{tabular}{lSSS}
\toprule
Operation & {Time/Op (\si{\micro\second})} & {Count (exchange)} & {Count (clients)} \\
\midrule
ecdh eddsa & 1338.62 & 2430 & 3645 \\
ecdhe key create & 1825.38 & 0 & 3645 \\
ecdhe key get public & 1272.64 & 2430 & 4860 \\
eddsa ecdh & 1301.78 & 0 & 4860 \\
eddsa key create & 1896.27 & 0 & 12180 \\
eddsa key get public & 1729.69 & 9720 & 80340 \\
eddsa sign & 5182.33 & 13393 & 25608 \\
eddsa verify & 3976.96 & 25586 & 25627 \\
hash & 1.41 & 165608 & 169445 \\
hash context finish & 0.28 & 1215 & 1227 \\
hash context read & 0.81 & 25515 & 25655 \\
hash context start & 11.38 & 1215 & 1227 \\
hkdf & 40.61 & 65057 & 193506 \\
rsa blind & 695.25 & 9720 & 31633 \\
rsa private key get public & 5.30 & 0 & 40 \\
rsa sign blinded & 5284.88 & 17053 & 0 \\
rsa unblind & 1348.62 & 0 & 21898 \\
rsa verify & 421.19 & 13393 & 29216 \\
\bottomrule
\end{tabular}
\caption{Cryptographic operations in the benchmark with one client and $10000$ operations.}
\label{table:benchmark:ops-baseline}
\end{table}
\begin{table}
\centering
\begin{tabular}{lSSS}
\toprule
\textbf{Relation} &
{\textbf{Table (\si{\mebi\byte})}} &
{\textbf{Indexes (\si{\mebi\byte})}} &
{\textbf{Total (\si{\mebi\byte})}} \\
\midrule
denominations & 0.02 & 0.03 & 0.05 \\
reserves\_in & 0.01 & 0.08 & 0.09 \\
reserves & 0.02 & 0.25 & 0.27 \\
refresh\_commitments & 0.36 & 0.28 & 0.64 \\
refresh\_transfer\_keys & 0.38 & 0.34 & 0.73 \\
refresh\_revealed\_coins & 4.19 & 0.91 & 5.14 \\
known\_coins & 7.37 & 0.70 & 8.07 \\
deposits & 4.85 & 6.80 & 11.66 \\
reserves\_out & 8.95 & 4.48 & 13.43 \\
\midrule
\emph{Sum} & 26.14 & 13.88 & 40.02 \\
\bottomrule
\end{tabular}
\caption{Space usage by database table for $10000$ deposits with $10\%$ refresh probability.}
\label{table:exchange-db-size}
\end{table}
The size of the exchange's database after the experiment (starting from an empty database)
is shown in Table~\ref{table:exchange-db-size}.
We measured the size of tables and indexes using the \texttt{pg\_relation\_size} /
\texttt{pg\_indexes\_size} functions of PostgreSQL.
We observe that even though the refresh operations account for about half of
the time taken by the benchmark, they contribute to only $\approx 16\%$ of the
database's size. The computational costs for refresh are higher than the
storage costs (compared to other operations), as the database stores only needs
to store one commitment, one transfer key and the blinded coins that are
actually signed.
In our sequential baseline benchmark run, only one reserve was used to withdraw
coins, and thus the tables that store the reserves are very small. In
practice, information for multiple reserves would be tracked for each active
cutomers.
The TCP/IP network traffic between the exchange, clients and the mock bank was
$\SI{57.95}{\mebi\byte}$, measured by the Linux kernel's statistics for
transmitted/received bytes on the relevant network interface. As expected, the
traffic is larger than the size of the database, since some data (such as
signatures) is only verified/generated and not stored in the database.
\subsection{Transaction Rate and Scalability}
Figure~\ref{fig:benchmark-throughput} shows the mean time taken to process one
coin for different numbers of parallel clients. With increasing parallelism,
the throughput continues to rise roughly until after the number of parallel
clients saturates the number of available CPU cores (96). There is no
significant decrease in throughput even when the system is under rather high
load, as clients whose requests cannot be handled in parallel are either
waiting in the exchange's listen backlog or waiting in a retry timeout
(with randomized, truncated, exponential back-off) after being refused when the
exchange's listen backlog is full.
Figure~\ref{fig:benchmark-cpu} shows the CPU time (sum of user and system time)
of both the exchange and the whole benchmark testbed (including the exchange)
in relation to the wall-clock time the benchmark took to complete.
We can see that the gap between the wall-clock time and CPU time used by the
benchmark grows with an increase in the number of parallel clients. This can
be explained by the CPU usage of the database (whose CPU usage is not measured
as part of the benchmark). With a growing number of parallel transactions, the
database runs into an increasing number of failed commits due to read/write
conflicts, leading to retries of the corresponding transactions.
To estimate the time taken up by cryptographic operations in the exchange, we
first measured a baseline with a single client, where the wall-clock time for
cryptographic operations is very close to the actual CPU time, as virtually no
context switching occurs. We then extrapolated these timings to experiment
runs with parallelism by counting the number of times each operation is
executed and multiplying with the baseline. As seen in the dot-and-dash line
in Figure~\ref{fig:benchmark-cpu}, by our extrapolation slightly more than half
of the time is spent in cryptographic routines.
We furthermore observe in Figure~\ref{fig:benchmark-cpu} that under full load,
less than $1/3$ of the CPU time is spent by the exchange. A majority of the
CPU time in the benchmark is used by the simulation of clients.
As we did not have a machine available that is powerful enough to generate
traffic that can saturate a single exchange running on \texttt{firefly}, we
estimate the throughput that would be possible if the machine only ran the
exchange. The highest rate of spends was $780$ per second. Thus, the
theoretically achievable transaction rate on our single test machine (and a
dedicated machine for the database) would be $780 \cdot 3 / 10 = 234$ transactions
per second under the relatively pessimistic assumptions we made about what
constitutes a transaction.
If a GNU Taler deployment was used to pay for items of fixed price (e.g., online
news articles), the overhead of multiple coins and refresh operations (which
accounts for $\approx 50\%$ of spent time as measured earlier) and multiple
coins per payment would vanish, giving an estimated maximum transaction rate of
$742 \cdot 2 = 1484$ transactions per second.
\begin{figure}
\includegraphics[width=\textwidth]{plots/speed.pdf}
\caption[Coin throughput.]{Coin throughput in relation to number of parallel clients, with $1000$ coins per client per experiment run.}
\label{fig:benchmark-throughput}
\end{figure}
\begin{figure}
\includegraphics[width=\textwidth]{plots/cpu.pdf}
\caption[Comparison of components' CPU usage for the benchmark.]{Comparison of real time, the CPU time for the exchange and the whole benchmark.}
\label{fig:benchmark-cpu}
\end{figure}
\subsection{Latency}
We connected \texttt{firefly} and \texttt{gv} directly with a patch cable, and
introduced artificial network latency by configuring the Linux packet scheduler
with the \texttt{tc} tool. The goal of this experiment was to observe the
network latency characteristics of the implementation. Note that we do not consider
the overhead of TLS in our experiments, as we assume that TLS traffic is
already terminated before it reaches the exchange service, and exchanges can be
operated securely even without TLS.
The comparison between no additional delay and a \SI{100}{\milli\second} delay
is shown in Table~\ref{table:latency}. TCP Fast Open~\cite{rfc7413} was
enabled on both \texttt{gv} and \texttt{firefly}. Since for all operations
except \texttt{/refresh/reveal}, both request and response fit into one TCP
segment, these operations complete within one round-trip time. This explains the
additional delay of $\approx \SI{200}{\milli\second}$ when the artificial delay
is introduced. Without TCP Fast Open, we would observe an extra round trip for
the SYN and SYN/ACK packages without any payload. The \texttt{/refresh/reveal}
operation takes an extra roundtrip due to the relatively large size of the
request (as show in Table~\ref{table:api-size}), which exceeds the MTU of 1500
for the link between \texttt{gv} and \texttt{firefly}, and thus does not fit
into the first TCP Fast Open packet.
Figure~\ref{fig:latencies} shows the latency for the exchange's HTTP endpoints
in relation to different network delays. As expected, the additional delay
grows linearly for a single client. We note that in larger benchmarks with
multiple parallel clients, the effect of additional delay would likely not just
be linear, due to timeouts raised by clients.
\newcommand{\specialcell}[2][c]{%
\begin{tabular}[#1]{@{}c@{}}#2\end{tabular}}
\begin{table}
\centering
\begin{tabular}{lSSSS}
\toprule
Endpoint &
{\specialcell[c]{Base latency\\(\si{\milli\second})}} &
{\specialcell[c]{Latency with\\\SI{100}{\milli\second} delay\\(\si{\milli\second})}} \\
\midrule
\texttt{/keys} & 1.14 & 201.25 \\
\texttt{/reserve/withdraw} & 22.68 & 222.46 \\
\texttt{/deposit} & 22.36 & 223.22 \\
\texttt{/refresh/melt} & 20.71 & 223.9 \\
\texttt{/refresh/reveal} & 63.64 & 466.30 \\
\bottomrule
\end{tabular}
\caption{Effects of \SI{100}{\milli\second} symmetric network delay on total latency.}
\label{table:latency}
\end{table}
\begin{table}
\centering
\begin{tabular}{lSSSS}
\toprule
Endpoint &
{\specialcell[c]{Request size\\2048-bit RSA\\(\si{\kilo\byte})}} &
{\specialcell[c]{Response size\\2048-bit RSA\\(\si{\kilo\byte})}} &
{\specialcell[c]{Request size\\1024-bit RSA\\(\si{\kilo\byte})}} &
{\specialcell[c]{Response size\\1024-bit RSA\\(\si{\kilo\byte})}} \\
\midrule
\texttt{/keys} & 0.14 & 3.75 & 0.14 & 3.43 \\
\texttt{/reserve/withdraw} & 0.73 & 0.71 & 0.60 & 0.49 \\
\texttt{/deposit} & 1.40 & 0.34 & 1.14 & 0.24 \\
\texttt{/refresh/melt} & 1.06 & 0.35 & 0.85 & 0.35 \\
\texttt{/refresh/reveal} & 1.67 & 2.11 & 1.16 & 1.23 \\
\bottomrule
\end{tabular}
\caption[Request and response sizes for the exchange's API.]{Request and response sizes for the exchange's API.
In addition to the sizes for 2048-bit RSA keys (used throughout the benchmark), the sizes for 1024-bit RSA keys are also provided.}
\label{table:api-size}
\end{table}
\begin{figure}
\includegraphics[width=\textwidth]{plots/latencies.pdf}
\caption[Effect of artificial network delay on exchange's latency.]{Effect of artificial network delay on exchange's latency.}
\label{fig:latencies}
\end{figure}
% Missing benchmarks:
% overall Taler tx/s
% db io+tx/s
% If I have time:
% traffic/storage depending on key size?
\section{Current Limitations and Future Improvements}\label{sec:implementation-improvements}
Currently the auditor does not support taking samples of deposit confirmations that
merchants receive. The API and user interface to receive and process proofs
of misbehavior of the exchange/merchant generated by the wallet is not implemented yet.
As a real-world deployment of electronic cash has rather high requirements for
the operational security, the usage of hardware security modules for generation
of signatures should be considered. Currently, a single process has access to
all key material. For a lower-cost improvement that decreases the performance
of the system, a threshold signature scheme could be used.
The current implementation is focused on web payments. To use GNU Taler for
payments in brick-and-mortar stores, hardware wallets and smartphone apps for
devices with near-field-communication (NFC) must be developed. In some
scenarios, either the customer or the merchant might not have an Internet
connection, and this must be considered in the protocol design. In typical
western brick-and-mortar stores, it is currently more likely that the merchant
has Internet connectivity, and thus the protocol must allow operations of the
wallet (such as refreshing) to be securely routed over the merchant's
connection. In other scenarios, typically in developing countries, the
merchant (for example, a street vendor) might not have Internet connection. If
the vendor has a smartphone, the connection to the merchant can be routed
through the customer. In other cases, street vendors only have a ``dumb
phone'' that can receive text messages, and the payment goes through a provider
trusted by the merchant that sends text messages as confirmation for payments.
All these possibilities must be considered both from the perspective of the procotol and APIs
as well as the user experience.
% FIXME: explain that exchange does threading
Our experiments were only done with single exchange process and a single
database on the same machine. There are various ways to horizontally scale the
exchange:
\begin{itemize}
\item Multiple exchange processes can be run on multiple machines and access
the database that runs a separate machine. Requests are directed to the
machines running the exchange process via a load balancer. In this
scenario, the throughput of the database is likely to be the bottleneck.
\item To avoid having the database as a bottleneck, the contents can be
partitioned into shards. For this technique to be effective, data in the
shards should not have any dependencies in other shards. A natural way to
do sharding for the Taler exchange is to give each shard the sole
responsibility for a subset of all available denominations.
\item If the transaction volume on one denomination is too high to handle for
a single shard, transactions can be further partitioned based on the coin's
public key. Each would maintain the database of spent/refreshed coins for
a subset of all possible coin public keys. This approach has been
suggested for a centrally-banked cryprocurrency by Danezis and Meiklejohn
\cite{danezis2016rscoin}.
\end{itemize}
% paranoid wallet (permissions!)
% FIXME: I want to mention PADs for auditing/transparency somewhere, just
% because they're cool
% FIXME: coin locking not implemented!