aboutsummaryrefslogtreecommitdiff
path: root/src/util/wallet_signatures.c
diff options
context:
space:
mode:
authorChristian Grothoff <grothoff@gnunet.org>2022-03-22 02:33:51 +0100
committerChristian Grothoff <grothoff@gnunet.org>2022-03-22 02:33:51 +0100
commite200e860321abdff235863bd83e663ae57cf037a (patch)
treedd0c3429a3e0438fad970bfa2eee303b5c3c9ec5 /src/util/wallet_signatures.c
parentbdc797a5830983e22b42bf8d97c25d80ad9f6346 (diff)
downloadexchange-e200e860321abdff235863bd83e663ae57cf037a.tar.xz
implement helper functions for p2p signatures, clean up existing signature logic
Diffstat (limited to 'src/util/wallet_signatures.c')
-rw-r--r--src/util/wallet_signatures.c703
1 files changed, 703 insertions, 0 deletions
diff --git a/src/util/wallet_signatures.c b/src/util/wallet_signatures.c
index ef8870442..30903c6b7 100644
--- a/src/util/wallet_signatures.c
+++ b/src/util/wallet_signatures.c
@@ -23,6 +23,93 @@
#include "taler_signatures.h"
+/**
+ * @brief Format used to generate the signature on a request to deposit
+ * a coin into the account of a merchant.
+ */
+struct TALER_DepositRequestPS
+{
+ /**
+ * Purpose must be #TALER_SIGNATURE_WALLET_COIN_DEPOSIT.
+ * Used for an EdDSA signature with the `struct TALER_CoinSpendPublicKeyP`.
+ */
+ struct GNUNET_CRYPTO_EccSignaturePurpose purpose;
+
+ /**
+ * Hash over the contract for which this deposit is made.
+ */
+ struct TALER_PrivateContractHashP h_contract_terms GNUNET_PACKED;
+
+ /**
+ * Hash over the age commitment that went into the coin. Maybe all zero, if
+ * age commitment isn't applicable to the denomination.
+ */
+ struct TALER_AgeCommitmentHash h_age_commitment GNUNET_PACKED;
+
+ /**
+ * Hash over extension attributes shared with the exchange.
+ */
+ struct TALER_ExtensionContractHashP h_extensions GNUNET_PACKED;
+
+ /**
+ * Hash over the wiring information of the merchant.
+ */
+ struct TALER_MerchantWireHashP h_wire GNUNET_PACKED;
+
+ /**
+ * Hash over the denomination public key used to sign the coin.
+ */
+ struct TALER_DenominationHashP h_denom_pub GNUNET_PACKED;
+
+ /**
+ * Time when this request was generated. Used, for example, to
+ * assess when (roughly) the income was achieved for tax purposes.
+ * Note that the Exchange will only check that the timestamp is not "too
+ * far" into the future (i.e. several days). The fact that the
+ * timestamp falls within the validity period of the coin's
+ * denomination key is irrelevant for the validity of the deposit
+ * request, as obviously the customer and merchant could conspire to
+ * set any timestamp. Also, the Exchange must accept very old deposit
+ * requests, as the merchant might have been unable to transmit the
+ * deposit request in a timely fashion (so back-dating is not
+ * prevented).
+ */
+ struct GNUNET_TIME_TimestampNBO wallet_timestamp;
+
+ /**
+ * How much time does the merchant have to issue a refund request?
+ * Zero if refunds are not allowed. After this time, the coin
+ * cannot be refunded.
+ */
+ struct GNUNET_TIME_TimestampNBO refund_deadline;
+
+ /**
+ * Amount to be deposited, including deposit fee charged by the
+ * exchange. This is the total amount that the coin's value at the exchange
+ * will be reduced by.
+ */
+ struct TALER_AmountNBO amount_with_fee;
+
+ /**
+ * Depositing fee charged by the exchange. This must match the Exchange's
+ * denomination key's depositing fee. If the client puts in an
+ * invalid deposit fee (too high or too low) that does not match the
+ * Exchange's denomination key, the deposit operation is invalid and
+ * will be rejected by the exchange. The @e amount_with_fee minus the
+ * @e deposit_fee is the amount that will be transferred to the
+ * account identified by @e h_wire.
+ */
+ struct TALER_AmountNBO deposit_fee;
+
+ /**
+ * The Merchant's public key. Allows the merchant to later refund
+ * the transaction or to inquire about the wire transfer identifier.
+ */
+ struct TALER_MerchantPublicKeyP merchant;
+
+};
+
+
void
TALER_wallet_deposit_sign (
const struct TALER_Amount *amount,
@@ -116,6 +203,41 @@ TALER_wallet_deposit_verify (
}
+/**
+ * @brief Format used for to allow the wallet to authenticate
+ * link data provided by the exchange.
+ */
+struct TALER_LinkDataPS
+{
+
+ /**
+ * Purpose must be #TALER_SIGNATURE_WALLET_COIN_LINK.
+ * Used with an EdDSA signature of a `struct TALER_CoinPublicKeyP`.
+ */
+ struct GNUNET_CRYPTO_EccSignaturePurpose purpose;
+
+ /**
+ * Hash of the denomination public key of the new coin.
+ */
+ struct TALER_DenominationHashP h_denom_pub;
+
+ /**
+ * Transfer public key (for which the private key was not revealed)
+ */
+ struct TALER_TransferPublicKeyP transfer_pub;
+
+ /**
+ * Hash of the age commitment, if applicable. Can be all zero
+ */
+ struct TALER_AgeCommitmentHash h_age_commitment;
+
+ /**
+ * Hash of the blinded new coin.
+ */
+ struct TALER_BlindedCoinHashP coin_envelope_hash;
+};
+
+
void
TALER_wallet_link_sign (const struct TALER_DenominationHashP *h_denom_pub,
const struct TALER_TransferPublicKeyP *transfer_pub,
@@ -161,6 +283,32 @@ TALER_wallet_link_verify (
}
+/**
+ * Signed data to request that a coin should be refunded as part of
+ * the "emergency" /recoup protocol. The refund will go back to the bank
+ * account that created the reserve.
+ */
+struct TALER_RecoupRequestPS
+{
+ /**
+ * Purpose is #TALER_SIGNATURE_WALLET_COIN_RECOUP
+ * or #TALER_SIGNATURE_WALLET_COIN_RECOUP_REFRESH.
+ */
+ struct GNUNET_CRYPTO_EccSignaturePurpose purpose;
+
+ /**
+ * Hash of the (revoked) denomination public key of the coin.
+ */
+ struct TALER_DenominationHashP h_denom_pub;
+
+ /**
+ * Blinding factor that was used to withdraw the coin.
+ */
+ union TALER_DenominationBlindingKeyP coin_blind;
+
+};
+
+
enum GNUNET_GenericReturnValue
TALER_wallet_recoup_verify (
const struct TALER_DenominationHashP *h_denom_pub,
@@ -243,6 +391,58 @@ TALER_wallet_recoup_refresh_sign (
}
+/**
+ * @brief Message signed by a coin to indicate that the coin should be
+ * melted.
+ */
+struct TALER_RefreshMeltCoinAffirmationPS
+{
+ /**
+ * Purpose is #TALER_SIGNATURE_WALLET_COIN_MELT.
+ * Used for an EdDSA signature with the `struct TALER_CoinSpendPublicKeyP`.
+ */
+ struct GNUNET_CRYPTO_EccSignaturePurpose purpose;
+
+ /**
+ * Which melt commitment is made by the wallet.
+ */
+ struct TALER_RefreshCommitmentP rc GNUNET_PACKED;
+
+ /**
+ * Hash over the denomination public key used to sign the coin.
+ */
+ struct TALER_DenominationHashP h_denom_pub GNUNET_PACKED;
+
+ /**
+ * If age commitment was provided during the withdrawal of the coin, this is
+ * the hash of the age commitment vector. It must be all zeroes if no age
+ * commitment was provided.
+ */
+ struct TALER_AgeCommitmentHash h_age_commitment GNUNET_PACKED;
+
+ /**
+ * How much of the value of the coin should be melted? This amount
+ * includes the fees, so the final amount contributed to the melt is
+ * this value minus the fee for melting the coin. We include the
+ * fee in what is being signed so that we can verify a reserve's
+ * remaining total balance without needing to access the respective
+ * denomination key information each time.
+ */
+ struct TALER_AmountNBO amount_with_fee;
+
+ /**
+ * Melting fee charged by the exchange. This must match the Exchange's
+ * denomination key's melting fee. If the client puts in an invalid
+ * melting fee (too high or too low) that does not match the Exchange's
+ * denomination key, the melting operation is invalid and will be
+ * rejected by the exchange. The @e amount_with_fee minus the @e
+ * melt_fee is the amount that will be credited to the melting
+ * session.
+ */
+ struct TALER_AmountNBO melt_fee;
+};
+
+
void
TALER_wallet_melt_sign (
const struct TALER_Amount *amount_with_fee,
@@ -308,6 +508,40 @@ TALER_wallet_melt_verify (
}
+/**
+ * @brief Format used for to generate the signature on a request to withdraw
+ * coins from a reserve.
+ */
+struct TALER_WithdrawRequestPS
+{
+
+ /**
+ * Purpose must be #TALER_SIGNATURE_WALLET_RESERVE_WITHDRAW.
+ * Used with an EdDSA signature of a `struct TALER_ReservePublicKeyP`.
+ */
+ struct GNUNET_CRYPTO_EccSignaturePurpose purpose;
+
+ /**
+ * Value of the coin being exchanged (matching the denomination key)
+ * plus the transaction fee. We include this in what is being
+ * signed so that we can verify a reserve's remaining total balance
+ * without needing to access the respective denomination key
+ * information each time.
+ */
+ struct TALER_AmountNBO amount_with_fee;
+
+ /**
+ * Hash of the denomination public key for the coin that is withdrawn.
+ */
+ struct TALER_DenominationHashP h_denomination_pub GNUNET_PACKED;
+
+ /**
+ * Hash of the (blinded) message to be signed by the Exchange.
+ */
+ struct TALER_BlindedCoinHashP h_coin_envelope GNUNET_PACKED;
+};
+
+
void
TALER_wallet_withdraw_sign (
const struct TALER_DenominationHashP *h_denom_pub,
@@ -374,6 +608,50 @@ TALER_wallet_account_setup_sign (
enum GNUNET_GenericReturnValue
+TALER_wallet_account_setup_verify (
+ const struct TALER_ReservePublicKeyP *reserve_pub,
+ const struct TALER_ReserveSignatureP *reserve_sig)
+{
+ struct GNUNET_CRYPTO_EccSignaturePurpose purpose = {
+ .size = htonl (sizeof (purpose)),
+ .purpose = htonl (TALER_SIGNATURE_WALLET_ACCOUNT_SETUP)
+ };
+
+ return GNUNET_CRYPTO_eddsa_verify_ (
+ TALER_SIGNATURE_WALLET_RESERVE_STATUS,
+ &purpose,
+ &reserve_sig->eddsa_signature,
+ &reserve_pub->eddsa_pub);
+}
+
+
+/**
+ * Response by which a wallet requests a full
+ * reserve history and indicates it is willing
+ * to pay for it.
+ */
+struct TALER_ReserveHistoryRequestPS
+{
+
+ /**
+ * Purpose is #TALER_SIGNATURE_WALLET_RESERVE_HISTORY
+ */
+ struct GNUNET_CRYPTO_EccSignaturePurpose purpose;
+
+ /**
+ * When did the wallet make the requst.
+ */
+ struct GNUNET_TIME_TimestampNBO request_timestamp;
+
+ /**
+ * How much does the exchange charge for the history?
+ */
+ struct TALER_AmountNBO history_fee;
+
+};
+
+
+enum GNUNET_GenericReturnValue
TALER_wallet_reserve_history_verify (
const struct GNUNET_TIME_Timestamp ts,
const struct TALER_Amount *history_fee,
@@ -417,6 +695,25 @@ TALER_wallet_reserve_history_sign (
}
+/**
+ * Response by which a wallet requests an account status.
+ */
+struct TALER_ReserveStatusRequestPS
+{
+
+ /**
+ * Purpose is #TALER_SIGNATURE_WALLET_RESERVE_STATUS
+ */
+ struct GNUNET_CRYPTO_EccSignaturePurpose purpose;
+
+ /**
+ * When did the wallet make the requst.
+ */
+ struct GNUNET_TIME_TimestampNBO request_timestamp;
+
+};
+
+
enum GNUNET_GenericReturnValue
TALER_wallet_reserve_status_verify (
const struct GNUNET_TIME_Timestamp ts,
@@ -455,4 +752,410 @@ TALER_wallet_reserve_status_sign (
}
+/**
+ * Message signed to create a purse (without reserve).
+ */
+struct TALER_PurseCreatePS
+{
+
+ /**
+ * Purpose is #TALER_SIGNATURE_WALLET_PURSE_CREATE
+ */
+ struct GNUNET_CRYPTO_EccSignaturePurpose purpose;
+
+ /**
+ * Time when the purse will expire if still unmerged or unpaid.
+ */
+ struct GNUNET_TIME_TimestampNBO purse_expiration;
+
+ /**
+ * Total amount (with fees) to be put into the purse.
+ */
+ struct TALER_AmountNBO purse_amount;
+
+ /**
+ * Contract this purse pays for.
+ */
+ struct TALER_PrivateContractHashP h_contract_terms;
+
+ /**
+ * Minimum age required for payments into this purse.
+ */
+ uint32_t min_age GNUNET_PACKED;
+
+};
+
+
+void
+TALER_wallet_purse_create_sign (
+ struct GNUNET_TIME_Timestamp purse_expiration,
+ struct TALER_PrivateContractHashP *h_contract_terms,
+ uint32_t min_age,
+ const struct TALER_Amount *amount,
+ const struct TALER_PursePrivateKeyP *purse_priv,
+ struct TALER_PurseSignatureP *purse_sig)
+{
+ struct TALER_PurseCreatePS pm = {
+ .purpose.size = htonl (sizeof (pm)),
+ .purpose.purpose = htonl (TALER_SIGNATURE_WALLET_PURSE_CREATE),
+ .purse_expiration = GNUNET_TIME_timestamp_hton (purse_expiration),
+ .h_contract_terms = *h_contract_terms,
+ .min_age = htonl (min_age)
+ };
+
+ TALER_amount_hton (&pm.purse_amount,
+ amount);
+ GNUNET_CRYPTO_eddsa_sign (&purse_priv->eddsa_priv,
+ &pm,
+ &purse_sig->eddsa_signature);
+}
+
+
+enum GNUNET_GenericReturnValue
+TALER_wallet_purse_create_verify (
+ struct GNUNET_TIME_Timestamp purse_expiration,
+ struct TALER_PrivateContractHashP *h_contract_terms,
+ uint32_t min_age,
+ const struct TALER_Amount *amount,
+ const struct TALER_PursePublicKeyP *purse_pub,
+ const struct TALER_PurseSignatureP *purse_sig)
+{
+ struct TALER_PurseCreatePS pm = {
+ .purpose.size = htonl (sizeof (pm)),
+ .purpose.purpose = htonl (TALER_SIGNATURE_WALLET_PURSE_CREATE),
+ .purse_expiration = GNUNET_TIME_timestamp_hton (purse_expiration),
+ .h_contract_terms = *h_contract_terms,
+ .min_age = htonl (min_age)
+ };
+
+ TALER_amount_hton (&pm.purse_amount,
+ amount);
+ return GNUNET_CRYPTO_eddsa_verify (
+ TALER_SIGNATURE_WALLET_PURSE_CREATE,
+ &pm,
+ &purse_sig->eddsa_signature,
+ &purse_pub->eddsa_pub);
+}
+
+
+void
+TALER_wallet_purse_status_sign (
+ const struct TALER_PursePrivateKeyP *purse_priv,
+ struct TALER_PurseSignatureP *purse_sig)
+{
+ struct GNUNET_CRYPTO_EccSignaturePurpose purpose = {
+ .size = htonl (sizeof (purpose)),
+ .purpose = htonl (TALER_SIGNATURE_WALLET_PURSE_STATUS)
+ };
+
+ GNUNET_assert (GNUNET_OK ==
+ GNUNET_CRYPTO_eddsa_sign_ (&purse_priv->eddsa_priv,
+ &purpose,
+ &purse_sig->eddsa_signature));
+}
+
+
+enum GNUNET_GenericReturnValue
+TALER_wallet_purse_status_verify (
+ const struct TALER_PursePublicKeyP *purse_pub,
+ const struct TALER_PurseSignatureP *purse_sig)
+{
+ struct GNUNET_CRYPTO_EccSignaturePurpose purpose = {
+ .size = htonl (sizeof (purpose)),
+ .purpose = htonl (TALER_SIGNATURE_WALLET_PURSE_STATUS)
+ };
+
+ return GNUNET_CRYPTO_eddsa_verify_ (TALER_SIGNATURE_WALLET_PURSE_STATUS,
+ &purpose,
+ &purse_sig->eddsa_signature,
+ &purse_pub->eddsa_pub);
+}
+
+
+/**
+ * Message signed to deposit a coin into a purse.
+ */
+struct TALER_PurseDepositPS
+{
+
+ /**
+ * Purpose is #TALER_SIGNATURE_WALLET_PURSE_DEPOSIT
+ */
+ struct GNUNET_CRYPTO_EccSignaturePurpose purpose;
+
+ /**
+ * Amount (with deposit fee) to be deposited into the purse.
+ */
+ struct TALER_AmountNBO coin_amount;
+
+ /**
+ * Purse to deposit funds into.
+ */
+ struct TALER_PursePublicKeyP purse_pub;
+
+};
+
+
+void
+TALER_wallet_purse_deposit_sign (
+ const struct TALER_PursePublicKeyP *purse_pub,
+ const struct TALER_Amount *amount,
+ const struct TALER_CoinSpendPrivateKeyP *coin_priv,
+ struct TALER_CoinSpendSignatureP *coin_sig)
+{
+ struct TALER_PurseDepositPS pm = {
+ .purpose.size = htonl (sizeof (pm)),
+ .purpose.purpose = htonl (TALER_SIGNATURE_WALLET_PURSE_DEPOSIT),
+ .purse_pub = *purse_pub,
+ };
+
+ TALER_amount_hton (&pm.coin_amount,
+ amount);
+ GNUNET_CRYPTO_eddsa_sign (&coin_priv->eddsa_priv,
+ &pm,
+ &coin_sig->eddsa_signature);
+}
+
+
+enum GNUNET_GenericReturnValue
+TALER_wallet_purse_deposit_verify (
+ const struct TALER_PursePublicKeyP *purse_pub,
+ const struct TALER_Amount *amount,
+ const struct TALER_CoinSpendPublicKeyP *coin_pub,
+ const struct TALER_CoinSpendSignatureP *coin_sig)
+{
+ struct TALER_PurseDepositPS pm = {
+ .purpose.size = htonl (sizeof (pm)),
+ .purpose.purpose = htonl (TALER_SIGNATURE_WALLET_PURSE_DEPOSIT),
+ .purse_pub = *purse_pub,
+ };
+
+ TALER_amount_hton (&pm.coin_amount,
+ amount);
+ return GNUNET_CRYPTO_eddsa_verify (
+ TALER_SIGNATURE_WALLET_PURSE_DEPOSIT,
+ &pm,
+ &coin_sig->eddsa_signature,
+ &coin_pub->eddsa_pub);
+}
+
+
+/**
+ * Message signed to merge a purse into a reserve.
+ */
+struct TALER_PurseMergePS
+{
+
+ /**
+ * Purpose is #TALER_SIGNATURE_WALLET_PURSE_MERGE
+ */
+ struct GNUNET_CRYPTO_EccSignaturePurpose purpose;
+
+ /**
+ * Time when the purse is merged into the reserve.
+ */
+ struct GNUNET_TIME_TimestampNBO merge_timestamp;
+
+ /**
+ * Which reserve should the purse be merged with.
+ * Hash of the reserve's payto:// URI.
+ */
+ struct TALER_PaytoHashP h_payto;
+
+};
+
+
+void
+TALER_wallet_purse_merge_sign (
+ const char *reserve_url,
+ struct GNUNET_TIME_Timestamp merge_timestamp,
+ const struct TALER_PursePrivateKeyP *purse_priv,
+ struct TALER_PurseSignatureP *purse_sig)
+{
+ struct TALER_PurseMergePS pm = {
+ .purpose.size = htonl (sizeof (pm)),
+ .purpose.purpose = htonl (TALER_SIGNATURE_WALLET_PURSE_MERGE),
+ .merge_timestamp = GNUNET_TIME_timestamp_hton (merge_timestamp),
+ };
+
+ TALER_payto_hash (reserve_url,
+ &pm.h_payto);
+ GNUNET_CRYPTO_eddsa_sign (&purse_priv->eddsa_priv,
+ &pm,
+ &purse_sig->eddsa_signature);
+}
+
+
+enum GNUNET_GenericReturnValue
+TALER_wallet_purse_merge_verify (
+ const char *reserve_url,
+ struct GNUNET_TIME_Timestamp merge_timestamp,
+ const struct TALER_PursePublicKeyP *purse_pub,
+ const struct TALER_PurseSignatureP *purse_sig)
+{
+ struct TALER_PurseMergePS pm = {
+ .purpose.size = htonl (sizeof (pm)),
+ .purpose.purpose = htonl (TALER_SIGNATURE_WALLET_PURSE_MERGE),
+ .merge_timestamp = GNUNET_TIME_timestamp_hton (merge_timestamp),
+ };
+
+ TALER_payto_hash (reserve_url,
+ &pm.h_payto);
+ return GNUNET_CRYPTO_eddsa_verify (
+ TALER_SIGNATURE_WALLET_ACCOUNT_MERGE,
+ &pm,
+ &purse_sig->eddsa_signature,
+ &purse_pub->eddsa_pub);
+}
+
+
+/**
+ * Message signed by account to merge a purse into a reserve.
+ */
+struct TALER_AccountMergePS
+{
+
+ /**
+ * Purpose is #TALER_SIGNATURE_WALLET_ACCOUNT_MERGE
+ */
+ struct GNUNET_CRYPTO_EccSignaturePurpose purpose;
+
+ /**
+ * Time when the purse will expire if still unmerged or unpaid.
+ */
+ struct GNUNET_TIME_TimestampNBO purse_expiration;
+
+ /**
+ * Total amount (with fees) to be put into the purse.
+ */
+ struct TALER_AmountNBO purse_amount;
+
+ /**
+ * Which reserve should the purse be merged with.
+ * Hash of the reserve's payto:// URI.
+ */
+ struct TALER_PaytoHashP h_payto;
+
+ /**
+ * Contract this purse pays for.
+ */
+ struct TALER_PrivateContractHashP h_contract_terms;
+
+ /**
+ * Purse to merge.
+ */
+ struct TALER_PursePublicKeyP purse_pub;
+
+ /**
+ * Time when the purse is merged into the reserve.
+ */
+ struct GNUNET_TIME_TimestampNBO merge_timestamp;
+
+ /**
+ * Minimum age required for payments into this purse.
+ */
+ uint32_t min_age GNUNET_PACKED;
+};
+
+
+void
+TALER_wallet_account_merge_sign (
+ const char *reserve_url,
+ struct GNUNET_TIME_Timestamp merge_timestamp,
+ const struct TALER_PursePublicKeyP *purse_pub,
+ struct GNUNET_TIME_Timestamp purse_expiration,
+ struct TALER_PrivateContractHashP *h_contract_terms,
+ const struct TALER_Amount *amount,
+ uint32_t min_age,
+ const struct TALER_ReservePrivateKeyP *reserve_priv,
+ struct TALER_ReserveSignatureP *reserve_sig)
+{
+ struct TALER_AccountMergePS pm = {
+ .purpose.size = htonl (sizeof (pm)),
+ .purpose.purpose = htonl (TALER_SIGNATURE_WALLET_ACCOUNT_MERGE),
+ .merge_timestamp = GNUNET_TIME_timestamp_hton (merge_timestamp),
+ .purse_pub = *purse_pub,
+ .purse_expiration = GNUNET_TIME_timestamp_hton (purse_expiration),
+ .h_contract_terms = *h_contract_terms,
+ .min_age = htonl (min_age)
+ };
+
+ TALER_amount_hton (&pm.purse_amount,
+ amount);
+ TALER_payto_hash (reserve_url,
+ &pm.h_payto);
+ GNUNET_CRYPTO_eddsa_sign (&reserve_priv->eddsa_priv,
+ &pm,
+ &reserve_sig->eddsa_signature);
+}
+
+
+enum GNUNET_GenericReturnValue
+TALER_wallet_account_merge_verify (
+ const char *reserve_url,
+ struct GNUNET_TIME_Timestamp merge_timestamp,
+ const struct TALER_PursePublicKeyP *purse_pub,
+ struct GNUNET_TIME_Timestamp purse_expiration,
+ struct TALER_PrivateContractHashP *h_contract_terms,
+ const struct TALER_Amount *amount,
+ uint32_t min_age,
+ const struct TALER_ReservePublicKeyP *reserve_pub,
+ const struct TALER_ReserveSignatureP *reserve_sig)
+{
+ struct TALER_AccountMergePS pm = {
+ .purpose.size = htonl (sizeof (pm)),
+ .purpose.purpose = htonl (TALER_SIGNATURE_WALLET_ACCOUNT_MERGE),
+ .merge_timestamp = GNUNET_TIME_timestamp_hton (merge_timestamp),
+ .purse_pub = *purse_pub,
+ .purse_expiration = GNUNET_TIME_timestamp_hton (purse_expiration),
+ .h_contract_terms = *h_contract_terms,
+ .min_age = htonl (min_age)
+ };
+
+ TALER_amount_hton (&pm.purse_amount,
+ amount);
+ TALER_payto_hash (reserve_url,
+ &pm.h_payto);
+ return GNUNET_CRYPTO_eddsa_verify (
+ TALER_SIGNATURE_WALLET_ACCOUNT_MERGE,
+ &pm,
+ &reserve_sig->eddsa_signature,
+ &reserve_pub->eddsa_pub);
+}
+
+
+void
+TALER_wallet_account_close_sign (
+ const struct TALER_ReservePrivateKeyP *reserve_priv,
+ struct TALER_ReserveSignatureP *reserve_sig)
+{
+ struct GNUNET_CRYPTO_EccSignaturePurpose purpose = {
+ .size = htonl (sizeof (purpose)),
+ .purpose = htonl (TALER_SIGNATURE_WALLET_RESERVE_CLOSE)
+ };
+
+ GNUNET_assert (GNUNET_OK ==
+ GNUNET_CRYPTO_eddsa_sign_ (&reserve_priv->eddsa_priv,
+ &purpose,
+ &reserve_sig->eddsa_signature));
+}
+
+
+enum GNUNET_GenericReturnValue
+TALER_wallet_account_close_verify (
+ const struct TALER_ReservePublicKeyP *reserve_pub,
+ const struct TALER_ReserveSignatureP *reserve_sig)
+{
+ struct GNUNET_CRYPTO_EccSignaturePurpose purpose = {
+ .size = htonl (sizeof (purpose)),
+ .purpose = htonl (TALER_SIGNATURE_WALLET_RESERVE_CLOSE)
+ };
+
+ return GNUNET_CRYPTO_eddsa_verify_ (TALER_SIGNATURE_WALLET_RESERVE_CLOSE,
+ &purpose,
+ &reserve_sig->eddsa_signature,
+ &reserve_pub->eddsa_pub);
+}
+
+
/* end of wallet_signatures.c */