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 /core | |
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
Diffstat (limited to 'core')
-rw-r--r-- | core/api-common.rst | 16 | ||||
-rw-r--r-- | core/api-exchange.rst | 363 | ||||
-rw-r--r-- | core/api-merchant.rst | 39 |
3 files changed, 347 insertions, 71 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; + } -------- |