diff options
author | Christian Grothoff <christian@grothoff.org> | 2023-01-11 17:33:20 +0100 |
---|---|---|
committer | Christian Grothoff <christian@grothoff.org> | 2023-01-11 17:33:20 +0100 |
commit | e6f46fe0a17a3b16289e5c39d8bdc3b8f1e42c3b (patch) | |
tree | 61183a733d5d478576067f9874fe8f39cd83a676 | |
parent | 55e214061688073779f305abe6432c65b718c9a9 (diff) | |
parent | 4e9f6c11c7652c30cee8a65e22557f82e36badcf (diff) | |
download | docs-e6f46fe0a17a3b16289e5c39d8bdc3b8f1e42c3b.tar.gz docs-e6f46fe0a17a3b16289e5c39d8bdc3b8f1e42c3b.tar.bz2 docs-e6f46fe0a17a3b16289e5c39d8bdc3b8f1e42c3b.zip |
Merge branch 'master' of git+ssh://git.taler.net/docs
-rw-r--r-- | core/api-common.rst | 16 | ||||
-rw-r--r-- | core/api-exchange.rst | 363 | ||||
-rw-r--r-- | core/api-merchant.rst | 39 | ||||
-rw-r--r-- | design-documents/024-age-restriction.rst | 99 |
4 files changed, 445 insertions, 72 deletions
diff --git a/core/api-common.rst b/core/api-common.rst index b2913b47..ab158e79 100644 --- a/core/api-common.rst +++ b/core/api-common.rst @@ -633,6 +633,7 @@ uses 512-bit hash codes (64 bytes). struct GNUNET_ShortHashCode hash; }; +.. _BlindedCoinHash: .. sourcecode:: c struct TALER_BlindedCoinHash { @@ -830,6 +831,21 @@ within the struct TALER_BlindedCoinHash h_coin_envelope; }; +.. _TALER_AgeWithdrawRequestPS: +.. sourcecode:: c + + struct TALER_AgeWithdrawRequestPS { + /** + * purpose.purpose = TALER_SIGNATURE_WALLET_RESERVE_AGE_WITHDRAW + */ + struct GNUNET_CRYPTO_EccSignaturePurpose purpose; + struct TALER_ReservePublicKeyP reserve_pub; + struct GNUNET_HashCode age_restricted_coins_commitment; + struct GNUNET_HashCode h_denoms_h; + uint8 max_age_group; + }; + + .. _TALER_DepositRequestPS: .. sourcecode:: c diff --git a/core/api-exchange.rst b/core/api-exchange.rst index 6b7031c0..734a17cf 100644 --- a/core/api-exchange.rst +++ b/core/api-exchange.rst @@ -132,6 +132,15 @@ possibly by using HTTPS. // The exchange's signing keys. signkeys: SignKey[]; + // Optional field with a dictionary of (name, object) pairs defining the + // supported and enabled extensions, such as ``age_restriction``. + extensions?: { name: ExtensionManifest }; + + // Signature by the exchange master key of the SHA-256 hash of the + // normalized JSON-object of field extensions, if it was set. + // The signature has purpose TALER_SIGNATURE_MASTER_EXTENSIONS. + extensions_sig?: EddsaSignature; + // Compact EdDSA `signature` (binary-only) over the SHA-512 hash of the // concatenation of all SHA-512 hashes of the RSA denomination public keys // in ``denoms`` in the same order as they were in ``denoms``. Note that for @@ -1239,6 +1248,14 @@ exchange. interface ReserveSummary { // Balance left in the reserve. balance: Amount; + + // If set, age restriction is required to be set for each coin to this + // value during the withdrawal from this reserve. The client then MUST + // use a denomination with support for age restriction enabled for the + // withdrawal. + // The value represents a valid age group from the list of permissible + // age groups as defined by the exchange's output to /keys. + maximum_age_group?: number; } @@ -1283,6 +1300,10 @@ exchange. // Balance left in the reserve. balance: Amount; + // If set, gives the maximum age group that the client is required to set + // during withdrawal. + maximum_age_group: number; + // Transaction history for this reserve. // May be partial (!). history: TransactionHistoryItem[]; @@ -1297,6 +1318,7 @@ exchange. | AccountSetupTransaction | ReserveHistoryTransaction | ReserveWithdrawTransaction + | ReserveAgeWithdrawTransaction | ReserveCreditTransaction | ReserveClosingTransaction | ReserveOpenRequestTransaction @@ -1369,6 +1391,26 @@ exchange. withdraw_fee: Amount; } + .. ts:def:: ReserveAgeWithdrawTransaction + + interface ReserveAgeWithdrawTransaction { + type: "AGEWITHDRAW"; + + // Total Amount withdrawn. + amount: Amount; + + // Commitment of all ``n*kappa`` coins. + age_restricted_coins_commitment: HashCode; + + // Signature over a `TALER_AgeWithdrawRequestPS` + // with purpose ``TALER_SIGNATURE_WALLET_RESERVE_AGE_WITHDRAW`` + // created with the reserve's private key. + reserve_sig: EddsaSignature; + + // Fee that is charged for withdraw. + withdraw_fee: Amount; + } + .. ts:def:: ReserveCreditTransaction @@ -1569,6 +1611,68 @@ exchange. } +.. _delete-reserve: + +.. http:DELETE:: /reserves/$RESERVE_PUB + + Forcefully closes a reserve. + The request header must contain an *Account-Request-Signature*. + Note: this endpoint is not currently implemented! + + **Request:** + + *Account-Request-Signature*: The client must provide Base-32 encoded EdDSA signature made with ``$ACCOUNT_PRIV``, affirming its authorization to delete the account. The purpose used MUST be ``TALER_SIGNATURE_RESERVE_CLOSE``. + + :query force=BOOLEAN: *Optional.* If set to 'true' specified, the exchange + will delete the account even if there is a balance remaining. + + **Response:** + + :http:statuscode:`200 OK`: + The operation succeeded, the exchange provides details + about the account deletion. + The response will include a `ReserveClosedResponse` object. + :http:statuscode:`403 Forbidden`: + The *Account-Request-Signature* is invalid. + This response comes with a standard `ErrorDetail` response. + :http:statuscode:`404 Not found`: + The account is unknown to the exchange. + :http:statuscode:`409 Conflict`: + The account is still has digital cash in it, the associated + wire method is ``void`` and the *force* option was not provided. + This response comes with a standard `ErrorDetail` response. + + **Details:** + + .. ts:def:: ReserveClosedResponse + + interface ReserveClosedResponse { + + // Final balance of the account. + closing_amount: Amount; + + // Current time of the exchange, used as part of + // what the exchange signs over. + close_time: Timestamp; + + // Hash of the wire account into which the remaining + // balance will be transferred. Note: may be the + // hash over ``payto://void/`, in which case the + // balance is forfeit to the profit of the exchange. + h_wire: HashCode; + + // This is a signature over a + // struct ``TALER_AccountDeleteConfirmationPS`` with purpose + // ``TALER_SIGNATURE_EXCHANGE_RESERVE_CLOSED``. + exchange_sig: EddsaSignature; + + } + + + +Withdraw +~~~~~~~~ + .. http:post:: /csr-withdraw Obtain exchange-side input values in preparation for a @@ -1638,6 +1742,7 @@ exchange. r_pub_1: CsRPublic; } + .. http:post:: /reserves/$RESERVE_PUB/withdraw Withdraw a coin of the specified denomination. Note that the client should @@ -1830,6 +1935,10 @@ exchange. +Batch Withdraw +~~~~~~~~~~~~~~ + + .. http:post:: /reserves/$RESERVE_PUB/batch-withdraw Withdraw multiple coins from the same reserve. Note that the client should @@ -1844,10 +1953,9 @@ exchange. :http:statuscode:`200 OK`: The request was successful, and the response is a `BatchWithdrawResponse`. - Note that repeating exactly the same request - will again yield the same response, so if the network goes down during the - transaction or before the client can commit the coin signature to disk, the - coin is not lost. + Note that repeating exactly the same request will again yield the same + response, so if the network goes down during the transaction or before the + client can commit the coin signature to disk, the coin is not lost. :http:statuscode:`403 Forbidden`: A signature is invalid. This response comes with a standard `ErrorDetail` response. @@ -1862,14 +1970,14 @@ exchange. In this case, the wallet should repeat the exact same request later again using exactly the same blinded coin. :http:statuscode:`409 Conflict`: - The balance of the reserve is not sufficient to withdraw the coins of the indicated denominations. - The response is `WithdrawError` object. + The balance of the reserve is not sufficient to withdraw the coins of the + indicated denominations. The response is `WithdrawError` object. :http:statuscode:`410 Gone`: A requested denomination key is not yet or no longer valid. - It either before the validity start, past the expiration or was revoked. The response is a - `DenominationExpiredMessage`. Clients must evaluate - the error code provided to understand which of the - cases this is and handle it accordingly. + It either before the validity start, past the expiration or was revoked. + The response is a `DenominationExpiredMessage`. Clients must evaluate the + error code provided to understand which of the cases this is and handle it + accordingly. :http:statuscode:`451 Unavailable for Legal Reasons`: This reserve has received funds from a purse or the amount withdrawn exceeds another legal threshold and thus the reserve must @@ -1900,6 +2008,7 @@ exchange. } + .. ts:def:: BatchWithdrawResponse interface BatchWithdrawResponse { @@ -1909,64 +2018,211 @@ exchange. } +Withdraw with Age Restriction +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -.. _delete-reserve: - -.. http:DELETE:: /reserves/$RESERVE_PUB +If the reserve was marked with a maximum age group, the client has to perform a +cut&choose protocol with the exchange. It first calls +``/reserves/$RESERVE_PUB/age-withdraw`` and commits to ``n*kappa`` coins. On +success, the exchange answers this request with an noreveal-index. The client +then has to call ``/age-withdraw/$ACH/reveal`` to reveal all ``n*(kappa - 1)`` +coins along with their age commitments to proof that they were appropriate. +If so, the exchange will blindly sign ``n`` undisclosed coins from the request. - Forcefully closes a reserve. - The request header must contain an *Account-Request-Signature*. - Note: this endpoint is not currently implemented! - **Request:** +.. http:POST:: /reserves/$RESERVE_PUB/age-withdraw - *Account-Request-Signature*: The client must provide Base-32 encoded EdDSA signature made with ``$ACCOUNT_PRIV``, affirming its authorization to delete the account. The purpose used MUST be ``TALER_SIGNATURE_RESERVE_CLOSE``. + Withdraw multiple coins *with age restriction* from the same reserve. + Note that the client should commit all of the request details, including the + private key of the coins and the blinding factors, to disk *before* issuing + this request, so that it can recover the information if necessary in case of + transient failures, like power outage, network outage, etc. - :query force=BOOLEAN: *Optional.* If set to 'true' specified, the exchange - will delete the account even if there is a balance remaining. + **Request:** The request body must be a `AgeWithdrawRequest` object. **Response:** :http:statuscode:`200 OK`: - The operation succeeded, the exchange provides details - about the account deletion. - The response will include a `ReserveClosedResponse` object. + The request was successful, and the response is a `AgeWithdrawResponse`. + Note that repeating exactly the same request will again yield the same + response, so if the network goes down during the transaction or before the + client can commit the coin signature to disk, the coin is not lost. :http:statuscode:`403 Forbidden`: - The *Account-Request-Signature* is invalid. + A signature is invalid. This response comes with a standard `ErrorDetail` response. + :http:statuscode:`409 Conflict`: + The balance of the reserve is not sufficient to withdraw the coins of the + given amount. The response is a `WithdrawError` object. + :http:statuscode:`410 Gone`: + A requested denomination key is not yet or no longer valid. + It either before the validity start, past the expiration or was revoked. + The response is a `DenominationExpiredMessage`. Clients must evaluate the + error code provided to understand which of the cases this is and handle it + accordingly. + :http:statuscode:`451 Unavailable for Legal Reasons`: + This reserve has received funds from a purse or the amount withdrawn + exceeds another legal threshold and thus the reserve must + be upgraded to an account (with KYC) before the withdraw can + complete. Note that this response does NOT affirm that the + withdraw will ultimately complete with the requested amount. + The user should be redirected to the provided location to perform + the required KYC checks to open the account before withdrawing. + Afterwards, the request should be repeated. + The response will be an `KycNeededRedirect` object. + + .. ts:def:: AgeWithdrawRequest + + interface AgeWithdrawRequest { + // Commitment to the coins with age restriction. This is the SHA512 + // hash value $ACH over all n*kappa `BlindedCoinHash` values of all + // coins and their age commitments. It is alter used as part of the URL + // in the subsequent call to /age-withdraw/$ACH/reveal. + age_restricted_coins_commitment: HashCode; + + // The total amount that the client wants to withdraw from the reserve + // and must be at most the balance of the reserve. The balance of the + // reserve will be immediatley reduced by that amount. + // In the subsequent call to /age-withdraw/$ACH/reveal, the client has to + // provide the list of denominations (with support for age restriction) + // that the coins shall be signed with. The sum of the values of those + // denominations MUST equal this amount. + amount: Amount; + + // The maximum age group to commit to. MUST be the same as the maximum + // age group in the reserve. + max_age_group: number; + + // Signature of `TALER_AgeWithdrawRequestPS` created with + // the `reserves's private key <reserve-priv>` + // using purpose ``TALER_SIGNATURE_WALLET_RESERVE_AGE_WITHDRAW``. + reserve_sig: EddsaSignature; + } + + .. ts:def:: AgeWithdrawResponse + + interface AgeWithdrawResponse { + // index of the commitments that the client doesn't + // have to disclose + noreveal_index: Integer; + + // Signature of `TALER_AgeWithdrawRequestPS` whereby + // the exchange confirms the ``noreveal_index``. + exchange_sig: EddsaSignature; + + // `Public EdDSA key <sign-key-pub>` of the exchange that was used to + // generate the signature. Should match one of the exchange's signing + // keys from ``/keys``. Again given explicitly as the client might + // otherwise be confused by clock skew as to which signing key was used. + exchange_pub: EddsaPublicKey; + } + + + +.. http:POST:: /age-withdraw/$ACH/reveal + + The client has previously committed to multiple coins with age restriction + in a call to ``/reserve/$RESERVE_PUB/age-withdraw`` and got a + `AgeWithdrawResponse` from the exchange. By calling this + endpoint, the client has to reveal each coin and their ``kappa - 1`` + age commitments, except for the age commitments with index + ``noreveal_index``. The hash of all commitments from the former withdraw + request is given as the ``$ACH`` value in the URL to this endpoint. + + + **Request:** The request body must be a `AgeWithdrawRevealRequest` object. + + **Response:** + + :http:statuscode:`200 OK`: + The request was successful, and the response is a `BlindedSignaturesResponse`. + Note that repeating exactly the same request will again yield the same + response, so if the network goes down during the transaction or before the + client can commit the coin signature to disk, the coin is not lost. :http:statuscode:`404 Not found`: - The account is unknown to the exchange. + The provided commitment $ACH is unknown. :http:statuscode:`409 Conflict`: - The account is still has digital cash in it, the associated - wire method is ``void`` and the *force* option was not provided. - This response comes with a standard `ErrorDetail` response. + The reveal operation failed and the response is an `WithdrawError` object. + The error codes indicate one of two cases: - **Details:** + 1. An age commitment for one of the coins did not fulfill the required + maximum age requirement of the corresponding reserve. Error code: + ``TALER_EC_EXCHANGE_GENERIC_COIN_AGE_REQUIREMENT_FAILURE``. + 2. The sum of all denominations in the request is not equal to the amount + that was given in the previous commitment via the call to + /reserves/$RESERVE_PUB/age-withdraw. Error code: + ``TALER_EC_EXCHANGE_GENERIC_MISMATCH_OF_AMOUNT_AND_DENOMINATIONS``. - .. ts:def:: ReserveClosedResponse - interface ReserveClosedResponse { + .. ts:def:: AgeWithdrawRevealRequest - // Final balance of the account. - closing_amount: Amount; + interface AgeWithdrawRevealRequest { + // The public key of the reserve that was used for the initial commitment + // request. Needed for optimized database lookup. + reserve_pub: EddsaPublicKey; - // Current time of the exchange, used as part of - // what the exchange signs over. - close_time: Timestamp; + // Array of ``n`` hash codes of denomination public keys to order. + // These denominations MUST support age restriction as defined in the + // output to /keys. + // The sum of all denomination's values MUST equal the original amount + // of the previous commitment. + denoms_h: HashCode[]; - // Hash of the wire account into which the remaining - // balance will be transferred. Note: may be the - // hash over ``payto://void/`, in which case the - // balance is forfeit to the profit of the exchange. - h_wire: HashCode; + // Array of ``n`` entries with blinded coins, which are the non-desclosed + // coins in the previous commitment. They match the respective entries + // in ``denoms_h``. + coin_evs: CoinEnvelope[]; - // This is a signature over a - // struct ``TALER_AccountDeleteConfirmationPS`` with purpose - // ``TALER_SIGNATURE_EXCHANGE_RESERVE_CLOSED``. - exchange_sig: EddsaSignature; + // Array of ``n`` arrays of ``kappa - 1`` disclosed coin private keys, + // from which the associated age commitments are also derived. + disclosed_coins: DisclosedAgeRestrictedCoin[][]; + + } + + .. ts:def:: DisclosedAgeRestrictedCoin + + interface DisclosedAgeRestrictedCoin { + // A coin's private key. The associated blinding and age commitment for + // this coin MUST be derived from this private key as follows: + // + // Calculate the blinding beta as + // beta := HKDF(coin_priv, "blinding") + // + // If the denominations are for Clause-Schnorr-Signatures, calculate the + // nonce as + // nonce := HKDF(coin_priv, "cs-nonce") + // + // Let m â {1,...,M} be the maximum age group as defined in the reserve + // that the wallet can commit to. + // + // For age group $AG â {1,...m}, set + // seed = HDKF(coin_priv, "age-commitment", $AG) + // p[$AG] = Edx25519_generate_private(seed) + // and calculate the corresponding Edx25519PublicKey as + // q[$AG] = Edx25519_public_from_private(p[$AG]) + // + // For age groups $AG â {m,...,M}, set + // f[$AG] = HDKF(coin_priv, "age-factor", $AG) + // and calculate the corresponding Edx25519PublicKey as + // q[$AG] = Edx25519_derive_public(`PublishedAgeRestrictionBaseKey`, f[$AG]) + // + // Finally, with coin_priv and age commitment (q[]), the exchange + // will calculate the coin's public key coin_pub and use the + // TALER_CoinPubHashP(coin_pub, age_commitment_hash(q)) + // during the verification of the original age-withdraw-commitment. + coin_priv: EddsaPrivateKey; } + .. ts:def:: PublishedAgeRestrictionBaseKey + + // The value for ``PublishedAgeRestrictionBaseKey`` is a randomly chosen + // `Edx25519PublicKey` for which the private key is not known to the clients. It is + // used during the age-withdraw protocol so that clients can proof that they + // derived all public keys to age groups higher than their allowed maximum + // from this particular value. + const PublishedAgeRestrictionBaseKey = + new Edx25519PublicKey("DZJRF6HXN520505XDAWM8NMH36QV9J3VH77265WQ09EBQ76QSKCG"); + .. _deposit-par: @@ -2060,6 +2316,12 @@ proof to the seller for the escrow of sufficient fund. // Hash of denomination RSA key with which the coin is signed. denom_pub_hash: HashCode; + // IFF the corresponding denomination has support for + // age restriction enabled, this field MUST contain the SHA256 + // value of the age commitment that MUST have been provided during the + // purchase. + age_commitment_hash?: AgeCommitmentHash; + // Exchange's unblinded RSA signature of the coin. ub_sig: DenominationSignature; @@ -2922,6 +3184,10 @@ the API during normal operation. // denominations is of type Clause-Schnorr. rms?: RefreshMasterSeed; + // IFF the denomination has age restriction support, the client MUST + // provide the SHA256 hash of the age commitment of the coin. + // MUST be omitted otherwise. + age_commitment_hash?: AgeCommitmentHash; } For details about the HKDF used to derive the new coin private keys and @@ -3044,6 +3310,13 @@ the API during normal operation. // Signs over a `TALER_CoinLinkSignaturePS`. link_sigs: EddsaSignature[]; + // IFF the corresponding denomination has support for age restriction, + // the client MUST provide the original age commitment, i. e. the + // vector of public keys. + // The size of the vector MUST be the number of age groups as defined by the + // Exchange in the field ``.age_groups`` of the extension ``age_restriction``. + old_age_commitment?: Edx25519PublicKey[]; + } diff --git a/core/api-merchant.rst b/core/api-merchant.rst index ff03795a..f686b302 100644 --- a/core/api-merchant.rst +++ b/core/api-merchant.rst @@ -1575,7 +1575,7 @@ Inspecting inventory next_restock?: Timestamp; // Minimum age buyer must have (in years). - minimum_age: Integer; + minimum_age?: Integer; } @@ -3097,34 +3097,27 @@ Inspecting template :http:statuscode:`404 Not found`: The backend has does not know about the instance. - .. ts:def:: TemplateSummaryResponse interface TemplateSummaryResponse { - // List of templates that are present in our backend. - templates_list: TemplateEntry[]; - } - - + // List of templates that are present in our backend. + templates_list: TemplateEntry[]; + } The `TemplatesEntry` object describes a template. It has the following structure: - - .. ts:def:: TemplateEntry interface TemplateEntry { - // Template identifier, as found in the template. - template_id: string; - - // Human-readable description for the template. - template_description: string; - - } + // Template identifier, as found in the template. + template_id: string; + // Human-readable description for the template. + template_description: string; + } .. http:get:: [/instances/$INSTANCE]/private/templates/$TEMPLATE_ID @@ -3206,21 +3199,15 @@ Using template // The amount entered by the customer. amount?: Amount; - } - + } .. ts:def:: UsingTemplateResponse interface UsingTemplateResponse { - // After enter the request. The user will be pay with a taler URL. - taler_url: string; - } - - - - - + // After enter the request. The user will be pay with a taler URL. + taler_url: string; + } -------- diff --git a/design-documents/024-age-restriction.rst b/design-documents/024-age-restriction.rst index e2161688..5b6e091d 100644 --- a/design-documents/024-age-restriction.rst +++ b/design-documents/024-age-restriction.rst @@ -53,7 +53,7 @@ protocol, that gives the minor/ward a 1/Îș chance to raise the minimum age for the new coin). The proposed solution maintains the guarantees of GNU Taler with respect to -anonymity and unlinkability. We have published a paper +anonymity and unlinkability. We have published a paper `Zero Knowledge Age Restriction for GNU Taler <https://link.springer.com/chapter/10.1007/978-3-031-17140-6_6>`_ with the details. @@ -291,6 +291,7 @@ NULL, but only iff the corresponding denomination (indirectly referenced via table ``known_coins``) has ``.age_restricted`` set to true. This constraint can not be expressed reliably with SQL. + Protocol changes ---------------- @@ -371,6 +372,102 @@ accomodate for handling multiple coins at once -- thus multiplying the amount of data by the amount of coins in question--, but all with the same value of :math:`\gamma`. +The *actual* implementation of the protocol above will have a major optimization +to keep the bandwidth usage to a minimum. Instead of generating and sending +the age commitment (array of public keys) and blindings for each coin, the +wallet *MUST* derive the corresponding blindings and the age commitments from +the coin's private key itself as follows: + +Let + +- :math:`c_s` be the private key of the coin, +- :math:`m \in \{1,\ldots,M\}` be the maximum age (according to the reserve) + that a wallet can commit to during the withdrawal. +- :math:`P` be a published constant Edx25519-public-key to which the private + key is not known to any client. + + +Then calculate the blinding :math:`\beta` for the coin as + +.. math:: + \beta &:= \text{HKDF}(c_s, \text{"blinding"}) + +If the denomination is using Clause-Schnorr signatures, calculate the nonce +:math:`n` for the coin as + +.. math:: + n &:= \text{HKDF}(c_s, \text{"cs-nonce"}) + + + +For the age commitment, calculate: + +1. For age group :math:`a \in \{1,\ldots,m\}`, set + +.. math:: + s_a &:= \text{HDKF}(c_s, \text{"age-commitment"}, a) \\ + p_a &:= \text{Edx25519\_generate\_private}(s_a) \\ + q_a &:= \text{Edx25519\_public\_from\_private}(p_a) + +2. For age group :math:`a \in \{m,\ldots,M\}`, set + +.. math:: + f_a &:= \text{HDKF}(c_s, \text{"age-factor"}, a) \\ + q_a &:= \text{Edx25519\_derive\_public}(P, f_a). + +Then the vector :math:`\vec{q} = \{q_1,\ldots,q_M\}` is then the age commitment +associated to the coin's private key :math:`c_s`. For the non-disclosed coins, +the wallet can use the vector :math:`(p_1,\ldots,p_m,\bot,\ldots,\bot)` of +private keys for the attestation. + +Provided with the private key :math:`c_s`, the exchange can therefore calculate +the blinding :math:`\beta`, the nonce :math:`n` (if needed) and the age +commitment :math:`\vec{q}` itself, along with the coin's public key :math:`C_p` +and use the value of + +.. math:: + + \text{TALER\_CoinPubHashP}(C_p, \text{age\_commitment\_hash}(\vec{q})) + +during the verification of the original age-withdraw-commitment. + + +For the withdrawal with age restriction, a sketch of the corresponding database +schema in the exchange is given here: + +.. graphviz:: + + digraph deposit_policies { + rankdir = LR; + splines = true; + fontname="monospace" + node [ + fontname="monospace" + shape=record + ] + + subgraph cluster_commitments { + label=<<B>withdraw_age_commitments</B>> + margin=20 + commitments [ + label="<id>withdraw_age_commitments_id\l|h_commitment\l|amount_with_fee_val\l|amount_with_fee_frac\l|noreveal_index\l|max_age_group\l|<res>reserve_pub\l|reserve_sig\l|timestamp\l" + ] + } + + subgraph cluster_reveals { + label=<<B>withdraw_age_reveals</B>> + margin=20 + reveals [ + label="freshcoin_index\l|<comm>withdraw_age_commitments_id\l|<denom>denominations_serial\l|h_coin_ev\l" + ] + } + + commitments:res->reserves:id [ label="n:1"; fontname="monospace"]; + reveals:comm -> commitments:id [ label="n:1"; fontname="monospace" ]; + reveals:denom -> denominations:id [ label="n:1"; fontname="monospace"] ; + + } + Refresh - melting phase ~~~~~~~~~~~~~~~~~~~~~~~ |