Merge branch 'master' of git+ssh://git.taler.net/var/git/exchange
This commit is contained in:
commit
029911c757
1
.gitignore
vendored
1
.gitignore
vendored
@ -44,6 +44,7 @@ src/exchange-tools/taler-exchange-reservemod
|
||||
src/exchange-tools/taler-exchange-wire
|
||||
src/exchangedb/perf-exchangedb
|
||||
src/benchmark/taler-exchange-benchmark
|
||||
src/benchmark/test_benchmark_home/.local/share/taler/exchange/live-keys/
|
||||
src/json/test_json
|
||||
src/wire/test_sepa_wireformat
|
||||
src/wire/test_wire_plugin
|
||||
|
@ -583,6 +583,11 @@ protocol messages; denomination keys are used for blind-signing coins.
|
||||
The exchange's long-term offline key is assumed to be known to both
|
||||
customers and merchants and is certified by the auditors.
|
||||
|
||||
We avoid asking either customers or merchants to make trust desissions
|
||||
about individual exchanges. Instead, they need only select the auditors.
|
||||
Auditors must sign all the exchange's keys including, the individual
|
||||
denomination keys.
|
||||
|
||||
As we are dealing with financial transactions, we explicitly describe
|
||||
whenever entities need to safely commit data to persistent storage.
|
||||
As long as those commitments persist, the protocol can be safely
|
||||
@ -597,14 +602,20 @@ Merchants may discard information once payments from the exchange have
|
||||
been received, assuming the records are also no longer needed for tax
|
||||
purposes. The exchange's bank transfers dealing in traditional currency
|
||||
are expected to be recorded for tax authorities to ensure taxability.
|
||||
% FIXME: Auditor?
|
||||
|
||||
We use RSA for denomination keys and EdDSA over some eliptic curve
|
||||
$\mathbb{E}$ for all other keys. Let $G$ denote the generator of
|
||||
our elliptic curve $\mathbb{E}$.
|
||||
|
||||
|
||||
\subsection{Withdrawal}
|
||||
|
||||
Let $G$ be the generator of an elliptic curve. To withdraw anonymous
|
||||
digital coins, the customer first identifies a exchange with a
|
||||
denomination public-private key pair $K := (K_s, K_p)$ corresponding
|
||||
to a denomination the customer would like to withdraw, and then
|
||||
performs the following interaction with the exchange:
|
||||
To withdraw anonymous digital coins, the customer first selects an
|
||||
exchange and one of its public denomination public keys $K_p$ whose
|
||||
value $K_v$ corresponds to an amount the customer wishes to withdraw.
|
||||
We let $K_s$ denote the exchange's private key corresponding to $K_p$.
|
||||
Now the customer carries out the following interaction with the exchange:
|
||||
|
||||
% FIXME: We say withdrawal key in this document, but say reserve key in
|
||||
% others, so probably withdrawal key should be renamed to reserve key.
|
||||
@ -621,7 +632,7 @@ performs the following interaction with the exchange:
|
||||
\item coin key $C := (c_s,C_p)$ with private key $c_s$ and public key $C_p := c_s G$,
|
||||
\item blinding factor $b$, and commits $\langle W, C, b \rangle$ to disk.
|
||||
\end{itemize}
|
||||
\item The customer transfers an amount of money corresponding to at least $K_p$ to the exchange, with $W_p$ in the subject line of the transaction.
|
||||
\item The customer transfers an amount of money corresponding to at least $K_v$ to the exchange, with $W_p$ in the subject line of the transaction.
|
||||
\item The exchange receives the transaction and credits the $W_p$ reserve with the respective amount in its database.
|
||||
\item The customer sends $S_W(B_b(C_p))$ to the exchange to request withdrawal of $C$; here, $B_b$ denotes Chaum-style blinding with blinding factor $b$.
|
||||
\item The exchange checks if the same withdrawal request was issued before; in this case, it sends $S_{K}(B_b(C_p))$ to the customer.\footnote{$S_K$
|
||||
@ -636,6 +647,7 @@ performs the following interaction with the exchange:
|
||||
If the guards for the transaction fail, the exchange sends a descriptive error back to the customer,
|
||||
with proof that it operated correctly.
|
||||
Assuming the signature was valid, this would involve showing the transaction history for the reserve.
|
||||
% FIXME: Is it really the whole history?
|
||||
\item The customer computes and verifies the unblinded signature $S_K(C_p) = U_b(S_K(B_b(C_p)))$.
|
||||
The customer saves the coin $\langle S_K(C_p), c_s \rangle$ to local wallet on disk.
|
||||
\end{enumerate}
|
||||
@ -644,9 +656,12 @@ performs the following interaction with the exchange:
|
||||
\subsection{Exact and partial spending}
|
||||
|
||||
A customer can spend coins at a merchant, under the condition that the
|
||||
merchant trusts the specific exchange that issued the coin. Merchants are
|
||||
identified by their key $M := (m_s, M_p)$ where the public key $M_p$
|
||||
must be known to the customer a priori.
|
||||
merchant trusts the exchange that issued the coin.
|
||||
% FIXME: Auditor here?
|
||||
Merchants are identified by their public key $M_p = m_s G$ which the
|
||||
customer's wallet learns through the merchant's webpage, which itself
|
||||
must be authenticated with X.509c.
|
||||
% FIXME: Is this correct?
|
||||
|
||||
We now describe the protocol between the customer, merchant, and exchange
|
||||
for a transaction in which the customer spends a coin $C := (c_s, C_p)$
|
||||
@ -676,8 +691,8 @@ with signature $\widetilde{C} := S_K(C_p)$
|
||||
S_c(\widetilde{C}, m, f, H(a), H(p,r), M_p)$
|
||||
and sends $\langle \mathcal{D}, D_j\rangle$ to the merchant,
|
||||
where $D_j$ is the exchange which signed $K$.
|
||||
\item The merchant gives $(\mathcal{D}, p, r)$ to the exchange, revealing $p$
|
||||
only to the exchange.
|
||||
\item The merchant gives $(\mathcal{D}, p, r)$ to the exchange, thereby
|
||||
revealing $p$ only to the exchange.
|
||||
\item The exchange validates $\mathcal{D}$ and checks for double spending.
|
||||
If the coin has been involved in previous transactions and the new
|
||||
one would exceed its remaining value, it sends an error
|
||||
|
@ -38,6 +38,7 @@ libtalerfakebank_la_LIBADD = \
|
||||
-lgnunetjson \
|
||||
-lgnunetutil \
|
||||
-ljansson \
|
||||
-lmicrohttpd \
|
||||
$(XLIB)
|
||||
|
||||
|
||||
|
@ -20,3 +20,11 @@ taler_exchange_benchmark_LDADD = \
|
||||
-lgnunetcurl \
|
||||
-lgnunetutil \
|
||||
-ljansson
|
||||
|
||||
EXTRA_DIST = \
|
||||
taler-exchange-benchmark.conf \
|
||||
bank-details.json \
|
||||
merchant-details.json \
|
||||
test_benchmark_home/.local/share/taler/exchange/offline-keys/master.priv \
|
||||
test_benchmark_home/.config/taler/test.json \
|
||||
test_benchmark_home/.config/taler/sepa.json
|
||||
|
1
src/benchmark/bank_details.json
Normal file
1
src/benchmark/bank_details.json
Normal file
@ -0,0 +1 @@
|
||||
{"type":"test", "bank_uri":"http://localhost:8082/", "account_number":63}
|
@ -1 +1 @@
|
||||
{"type":"test", "bank_uri":"https://bank.test.taler.net/", "account_number":64}
|
||||
{"type":"test", "bank_uri":"http://localhost:8082/", "account_number":64}
|
||||
|
@ -1 +0,0 @@
|
||||
{"type":"test", "bank_uri":"https://bank.test.taler.net/", "account_number":63}
|
File diff suppressed because it is too large
Load Diff
@ -1,3 +1,91 @@
|
||||
[benchmark]
|
||||
SENDER_DETAILS = ~/exchange/src/benchmark/sender_details.json
|
||||
MERCHANT_DETAILS = ~/exchange/src/benchmark/merchant_details.json
|
||||
BANK_DETAILS = bank_details.json
|
||||
MERCHANT_DETAILS = merchant_details.json
|
||||
|
||||
[PATHS]
|
||||
# Persistant data storage for the testcase
|
||||
TALER_TEST_HOME = test_benchmark_home/
|
||||
|
||||
[taler]
|
||||
CURRENCY = KUDOS
|
||||
|
||||
[exchange]
|
||||
|
||||
# Wire format supported by the exchange
|
||||
# We use 'test' for testing of the actual
|
||||
# coin operations, and 'sepa' to test SEPA-specific routines.
|
||||
WIREFORMAT = test
|
||||
|
||||
# HTTP port the exchange listens to
|
||||
PORT = 8081
|
||||
# How to access our database
|
||||
DB = postgres
|
||||
|
||||
# Master public key used to sign the exchange's various keys
|
||||
MASTER_PUBLIC_KEY = 98NJW3CQHZQGQXTY3K85K531XKPAPAVV4Q5V8PYYRR00NJGZWNVG
|
||||
|
||||
[exchangedb-postgres]
|
||||
DB_CONN_STR = "postgres:///talercheck"
|
||||
|
||||
|
||||
[exchange-wire-outgoing-test]
|
||||
# What is the main website of the bank?
|
||||
# (Not used unless the aggregator is run.)
|
||||
BANK_URI = "http://localhost:8082/"
|
||||
# From which account at the 'bank' should outgoing wire transfers be made?
|
||||
BANK_ACCOUNT_NUMBER = 2
|
||||
|
||||
[exchange-wire-incoming-test]
|
||||
# This is the response we give out for the /wire request. It provides
|
||||
# wallets with the bank information for transfers to the exchange.
|
||||
TEST_RESPONSE_FILE = ${TALER_CONFIG_HOME}/test.json
|
||||
|
||||
|
||||
[coin_kudos_1]
|
||||
value = KUDOS:1
|
||||
duration_overlap = 5 minutes
|
||||
duration_withdraw = 7 days
|
||||
duration_spend = 2 years
|
||||
duration_legal = 3 years
|
||||
fee_withdraw = KUDOS:0.00
|
||||
fee_deposit = KUDOS:0.00
|
||||
fee_refresh = KUDOS:0.00
|
||||
fee_refund = KUDOS:0.00
|
||||
rsa_keysize = 1024
|
||||
|
||||
[coin_kudos_2]
|
||||
value = KUDOS:2
|
||||
duration_overlap = 5 minutes
|
||||
duration_withdraw = 7 days
|
||||
duration_spend = 2 years
|
||||
duration_legal = 3 years
|
||||
fee_withdraw = KUDOS:0.00
|
||||
fee_deposit = KUDOS:0.00
|
||||
fee_refresh = KUDOS:0.00
|
||||
fee_refund = KUDOS:0.00
|
||||
rsa_keysize = 1024
|
||||
|
||||
[coin_kudos_4]
|
||||
value = KUDOS:4
|
||||
duration_overlap = 5 minutes
|
||||
duration_withdraw = 7 days
|
||||
duration_spend = 2 years
|
||||
duration_legal = 3 years
|
||||
fee_withdraw = KUDOS:0.00
|
||||
fee_deposit = KUDOS:0.00
|
||||
fee_refresh = KUDOS:0.00
|
||||
fee_refund = KUDOS:0.00
|
||||
rsa_keysize = 1024
|
||||
|
||||
[coin_kudos_8]
|
||||
value = KUDOS:8
|
||||
duration_overlap = 5 minutes
|
||||
duration_withdraw = 7 days
|
||||
duration_spend = 2 years
|
||||
duration_legal = 3 years
|
||||
fee_withdraw = KUDOS:0.00
|
||||
fee_deposit = KUDOS:0.00
|
||||
fee_refresh = KUDOS:0.00
|
||||
fee_refund = KUDOS:0.00
|
||||
rsa_keysize = 1024
|
||||
|
||||
|
@ -0,0 +1,9 @@
|
||||
{
|
||||
"name": "Max Musterman",
|
||||
"bic": "COBADEFF370",
|
||||
"type": "sepa",
|
||||
"sig": "4EVRC2MCJPXQC8MC00831DNWEXMZAP4JQDDE1A7R6KR3MANG24RC1VQ55AX5A2E35S58VW1VSTENFTPHG5MWG9BSN8B8WXSV21KKW20",
|
||||
"address": "Musterstadt",
|
||||
"salt": "3KTM1ZRMWGEQPQ254S4R5R4Q8XM0ZYWTCTE01TZ76MVBSQ6RX7A5DR08WXVH1DCHR1R7ACRB7X0EVC2XDW1CBZM9WFSD9TRMZ90BR98",
|
||||
"iban": "DE89370400440532013000"
|
||||
}
|
@ -0,0 +1,8 @@
|
||||
{
|
||||
"salt": "AZPRFVJ58NM6M7J5CZQPJAH3EW5DYM52AEZ9Y1C1ER3W94QV8D8TQKF6CK8MYQRA9QMSKDQTGZ306ZS9GQ0M6R01CJ20KPP49WFDZK8",
|
||||
"name": "The exchange",
|
||||
"account_number": 3,
|
||||
"bank_uri": "http://localhost:8082/",
|
||||
"type": "test",
|
||||
"sig": "RPQXP9S4P8PQP7HEZQNRSZCT0ATNEP8GW0P5TPM34V5RX86FCD670V44R9NETSYDDKB8SZV7TKY9PAJYTY51D3VDWY9XXQ5BPFRXR28"
|
||||
}
|
@ -0,0 +1 @@
|
||||
p<EFBFBD>^<5E>-<2D>33<33><33>XX<>!<04>\0q<30><71><EFBFBD><EFBFBD><18>mU<6D>_<EFBFBD><5F>
|
@ -764,6 +764,7 @@ TALER_EXCHANGE_refresh_prepare (const struct TALER_CoinSpendPrivateKeyP *melt_pr
|
||||
unsigned int i;
|
||||
unsigned int j;
|
||||
struct GNUNET_HashContext *hash_context;
|
||||
struct TALER_Amount total;
|
||||
|
||||
/* build up melt data structure */
|
||||
for (i=0;i<TALER_CNC_KAPPA;i++)
|
||||
@ -799,10 +800,44 @@ TALER_EXCHANGE_refresh_prepare (const struct TALER_CoinSpendPrivateKeyP *melt_pr
|
||||
md.fresh_coins[i] = GNUNET_new_array (fresh_pks_len,
|
||||
struct FreshCoinP);
|
||||
for (j=0;j<fresh_pks_len;j++)
|
||||
{
|
||||
setup_fresh_coin (&md.fresh_coins[i][j],
|
||||
&fresh_pks[j]);
|
||||
}
|
||||
}
|
||||
|
||||
/* verify that melt_amount is above total cost */
|
||||
GNUNET_assert (GNUNET_OK ==
|
||||
TALER_amount_get_zero (melt_amount->currency,
|
||||
&total));
|
||||
for (j=0;j<fresh_pks_len;j++)
|
||||
{
|
||||
if ( (GNUNET_OK !=
|
||||
TALER_amount_add (&total,
|
||||
&total,
|
||||
&fresh_pks[j].value)) ||
|
||||
(GNUNET_OK !=
|
||||
TALER_amount_add (&total,
|
||||
&total,
|
||||
&fresh_pks[j].fee_withdraw)) )
|
||||
{
|
||||
GNUNET_break (0);
|
||||
free_melt_data (&md);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
if (1 ==
|
||||
TALER_amount_cmp (&total,
|
||||
melt_amount) )
|
||||
{
|
||||
/* Eh, this operation is more expensive than the
|
||||
@a melt_amount. This is not OK. */
|
||||
GNUNET_break (0);
|
||||
free_melt_data (&md);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
/* now compute melt session hash */
|
||||
hash_context = GNUNET_CRYPTO_hash_context_start ();
|
||||
for (i=0;i<fresh_pks_len;i++)
|
||||
|
@ -283,7 +283,8 @@ TALER_EXCHANGE_refund (struct TALER_EXCHANGE_Handle *exchange,
|
||||
"merchant_pub", GNUNET_JSON_from_data_auto (&rr.merchant),
|
||||
"merchant_sig", GNUNET_JSON_from_data_auto (&merchant_sig)
|
||||
);
|
||||
|
||||
GNUNET_assert (NULL != refund_obj);
|
||||
|
||||
rh = GNUNET_new (struct TALER_EXCHANGE_RefundHandle);
|
||||
rh->exchange = exchange;
|
||||
rh->cb = cb;
|
||||
|
@ -43,7 +43,7 @@ TEST_RESPONSE_FILE = ${TALER_CONFIG_HOME}/test.json
|
||||
[exchange-wire-outgoing-test]
|
||||
# What is the main website of the bank?
|
||||
BANK_URI = "http://localhost:8082/"
|
||||
# Into which account at the 'bank' should (incoming) wire transfers be made?
|
||||
# From which account at the 'bank' should outgoing wire transfers be made?
|
||||
BANK_ACCOUNT_NUMBER = 2
|
||||
|
||||
[coin_eur_ct_1]
|
||||
|
@ -807,13 +807,14 @@ exchange_keys_update_cointype (void *cls,
|
||||
&denomkey_issue);
|
||||
if (GNUNET_OK !=
|
||||
TALER_EXCHANGEDB_denomination_key_write (dkf,
|
||||
&denomkey_issue))
|
||||
&denomkey_issue))
|
||||
{
|
||||
fprintf (stderr,
|
||||
"Failed to write denomination key information to file `%s'.\n",
|
||||
dkf);
|
||||
*ret = GNUNET_SYSERR;
|
||||
GNUNET_CRYPTO_rsa_private_key_free (denomkey_issue.denom_priv.rsa_private_key);
|
||||
GNUNET_CRYPTO_rsa_public_key_free (denomkey_issue.denom_pub.rsa_public_key);
|
||||
return;
|
||||
}
|
||||
if ( (NULL != auditor_output_file) &&
|
||||
@ -828,9 +829,12 @@ exchange_keys_update_cointype (void *cls,
|
||||
auditorrequestfile,
|
||||
STRERROR (errno));
|
||||
*ret = GNUNET_SYSERR;
|
||||
GNUNET_CRYPTO_rsa_private_key_free (denomkey_issue.denom_priv.rsa_private_key);
|
||||
GNUNET_CRYPTO_rsa_public_key_free (denomkey_issue.denom_pub.rsa_public_key);
|
||||
return;
|
||||
}
|
||||
GNUNET_CRYPTO_rsa_private_key_free (denomkey_issue.denom_priv.rsa_private_key);
|
||||
GNUNET_CRYPTO_rsa_public_key_free (denomkey_issue.denom_pub.rsa_public_key);
|
||||
p.anchor = GNUNET_TIME_absolute_add (p.anchor,
|
||||
p.duration_spend);
|
||||
p.anchor = GNUNET_TIME_absolute_subtract (p.anchor,
|
||||
|
Loading…
Reference in New Issue
Block a user