commit ac0c4179e29b17fe5c9c0d5082c68a85bfd452f2
parent da68d442b4bdf9bf2e747c814c16134e43dba170
Author: Christian Grothoff <grothoff@gnunet.org>
Date: Mon, 14 Apr 2025 15:13:18 +0200
Merge branch 'master' of git+ssh://git.taler.net/taler-docs
Diffstat:
8 files changed, 503 insertions(+), 111 deletions(-)
diff --git a/checklists/checklist-demo-upgrade.rst b/checklists/checklist-demo-upgrade.rst
@@ -57,8 +57,8 @@ To run those test you need one wallet.
- |democheck| wallet withdrawal payto-URI
- trigger withdraw from wallet & copy URI
- - paste URI in bank & pay
- - wallet redirect to success
+ - paste URI in bank & pay more
+ - wallet redirect to success and receive more
- paste URI in bank & pay -> bounce
- |democheck| bank withdrawal success
diff --git a/core/api-challenger.rst b/core/api-challenger.rst
@@ -101,7 +101,7 @@ Receiving Configuration
.. http:get:: /config
Obtain the key configuration settings of the storage service.
- This specification corresponds to ``current`` protocol being version **5**.
+ This specification corresponds to ``current`` protocol being version **6**.
**Response:**
@@ -133,8 +133,14 @@ Receiving Configuration
// the user. See "ADDRESS_RESTRICTIONS" in the challenger configuration.
restrictions: Object;
- // @since **v2**.
- address_type: "email" | "phone";
+ // @since **v6**
+ // Defines the set of fields asked to the user.
+ // The field names are registered via `GANA <https://git.taler.net/gana.git/tree/gnu-taler-form-attributes>`_
+ // email: CONTACT_EMAIL
+ // phone: CONTACT_PHONE
+ // postal: CONTACT_PERSON_NAME, ADDRESS_LINES, ADDRESS_COUNTRY
+ // postal-ch: CONTACT_PERSON_NAME, ADDRESS_LINES
+ address_type: "email" | "phone" | "postal" | "postal-ch";
}
.. _challenger-setup:
diff --git a/core/api-exchange.rst b/core/api-exchange.rst
@@ -1557,7 +1557,7 @@ for details.
denom_pub_hash: HashCode;
}
-
+
.. ts:def:: BlindingPrepareResponse
@@ -1646,92 +1646,8 @@ exchange.
}
-CSR-Withdraw
-~~~~~~~~~~~~
-
-.. note:: This endpoint is deprecated starting with API version v26.
- Use ``/blinding-prepare`` instead.
-
-.. http:post:: /csr-withdraw
-
- Obtain exchange-side input values in preparation for a
- withdraw step for certain denomination cipher types,
- specifically at this point for Clause-Schnorr blind
- signatures.
-
- **Request:** The request body must be a `WithdrawPrepareRequest` object.
-
- **Response:**
-
- :http:statuscode:`200 OK`:
- The request was successful, and the response is a `WithdrawPrepareResponse`. Note that repeating exactly the same request
- will again yield the same response (assuming none of the denomination is expired).
- :http:statuscode:`404 Not found`:
- The denomination key is not known to the exchange.
- :http:statuscode:`410 Gone`:
- The 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
- `DenominationGoneMessage`. Clients must evaluate
- the error code provided to understand which of the
- cases this is and handle it accordingly.
-
- **Details:**
-
- .. ts:def:: WithdrawPrepareRequest
-
- interface WithdrawPrepareRequest {
-
- // Nonce to be used by the exchange to derive
- // its private inputs from. Must not have ever
- // been used before.
- nonce: CSNonce;
-
- // Hash of the public key of the denomination the
- // request relates to.
- denom_pub_hash: HashCode;
-
- }
-
- .. ts:def:: WithdrawPrepareResponse
-
- type WithdrawPrepareResponse =
- | ExchangeWithdrawValue;
-
- .. ts:def:: ExchangeWithdrawValue
-
- type ExchangeWithdrawValue = DenomCipher & (
- | ExchangeRsaWithdrawValue
- | ExchangeCsWithdrawValue
- );
-
- .. ts:def:: DenomCipher
-
- interface DenomCipher {
- cipher: "RSA" | "CS";
- }
-
- .. ts:def:: ExchangeRsaWithdrawValue
-
- interface ExchangeRsaWithdrawValue extends DenomCipher {
- cipher: "RSA";
- }
-
- .. ts:def:: ExchangeCsWithdrawValue
-
- interface ExchangeCsWithdrawValue extends DenomCipher {
- cipher: "CS";
-
- // CSR R0 value
- r_pub_0: CSRPublic;
-
- // CSR R1 value
- r_pub_1: CSRPublic;
- }
-
-
-Withdraw
-~~~~~~~~
+.. _withdraw:
.. http:post:: /withdraw
.. note::
@@ -1991,15 +1907,91 @@ Withdraw
}
+.. http:post:: /csr-withdraw
+
+ .. note:: This endpoint is deprecated starting with API version v26.
+ Use ``/blinding-prepare`` instead.
+
+ Obtain exchange-side input values in preparation for a
+ withdraw step for certain denomination cipher types,
+ specifically at this point for Clause-Schnorr blind
+ signatures.
+
+ **Request:** The request body must be a `WithdrawPrepareRequest` object.
+
+ **Response:**
+
+ :http:statuscode:`200 OK`:
+ The request was successful, and the response is a `WithdrawPrepareResponse`. Note that repeating exactly the same request
+ will again yield the same response (assuming none of the denomination is expired).
+ :http:statuscode:`404 Not found`:
+ The denomination key is not known to the exchange.
+ :http:statuscode:`410 Gone`:
+ The 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
+ `DenominationGoneMessage`. Clients must evaluate
+ the error code provided to understand which of the
+ cases this is and handle it accordingly.
+
+ **Details:**
+
+ .. ts:def:: WithdrawPrepareRequest
+
+ interface WithdrawPrepareRequest {
+
+ // Nonce to be used by the exchange to derive
+ // its private inputs from. Must not have ever
+ // been used before.
+ nonce: CSNonce;
+
+ // Hash of the public key of the denomination the
+ // request relates to.
+ denom_pub_hash: HashCode;
+
+ }
+
+ .. ts:def:: WithdrawPrepareResponse
+
+ type WithdrawPrepareResponse =
+ | ExchangeWithdrawValue;
+
+ .. ts:def:: ExchangeWithdrawValue
+
+ type ExchangeWithdrawValue = DenomCipher & (
+ | ExchangeRsaWithdrawValue
+ | ExchangeCsWithdrawValue
+ );
+
+ .. ts:def:: DenomCipher
+
+ interface DenomCipher {
+ cipher: "RSA" | "CS";
+ }
+
+ .. ts:def:: ExchangeRsaWithdrawValue
+
+ interface ExchangeRsaWithdrawValue extends DenomCipher {
+ cipher: "RSA";
+ }
+
+ .. ts:def:: ExchangeCsWithdrawValue
+
+ interface ExchangeCsWithdrawValue extends DenomCipher {
+ cipher: "CS";
+
+ // CSR R0 value
+ r_pub_0: CSRPublic;
+
+ // CSR R1 value
+ r_pub_1: CSRPublic;
+ }
-Batch Withdraw
-~~~~~~~~~~~~~~
.. http:post:: /reserves/$RESERVE_PUB/batch-withdraw
.. note::
This endpoint becomes deprecated starting with API version v26.
- Use the ``/withdraw`` endpoint instead, see `Withdraw`_.
+ Use the ``/withdraw`` endpoint instead, see `withdraw`_.
Withdraw multiple coins from the same reserve. Note that the client should
commit all of the request details, including the private key of the coins and
@@ -2110,7 +2102,7 @@ These endpoints are called by the client
the transfer public keys (linking the ownership of the old and new coin),
and the commitment to age restriction,
as proof that the age restriction was set correctly (if applicable).
-#. after a call to `Withdraw`_, *if* the original request had ``max_age`` set
+#. after a call to `withdraw`_, *if* the original request had ``max_age`` set
and the response was of type `AgeWithdrawResponse`.
Now the client has to disclose for each coin all but one of the κ secrets
that went into creating the blinded coin's planchets,
@@ -2306,7 +2298,7 @@ These endpoints are called by the client
// 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
+ // used during the age-withdraw protocol so that clients can prove that they
// derived all public keys to age groups higher than their allowed maximum
// from this particular value.
const PublishedAgeRestrictionBaseKey =
@@ -2329,14 +2321,16 @@ Reserve History
The GET request should come with the following HTTP headers:
- *If-None-Match*: The client MAY provide an ``If-None-Match`` header with an
- Etag. In that case, the server MUST additionally respond with an ``304``
- status code in case the reserve history matches the provided Etag.
+ ``If-None-Match``:
+ The client MAY provide an ``If-None-Match`` header with an
+ Etag. In that case, the server MUST additionally respond with an ``304``
+ status code in case the reserve history matches the provided Etag.
- *Taler-Reserve-History-Signature*: The client MUST provide Base-32 encoded
- EdDSA signature over a TALER_SIGNATURE_RESERVE_HISTORY_REQUEST made with
- the respective ``$RESERVE_PRIV``, affirming desire to download the current
- reserve transaction history.
+ ``Taler-Reserve-History-Signature``:
+ The client MUST provide Base-32 encoded
+ EdDSA signature over a ``TALER_SIGNATURE_RESERVE_HISTORY_REQUEST`` made with
+ the respective ``$RESERVE_PRIV``, affirming desire to download the current
+ reserve transaction history.
:query start=OFFSET: *Optional.* Only return reserve history entries with
offsets above the given OFFSET. Allows clients to not
@@ -2479,8 +2473,9 @@ Reserve History
// call to /withdraw.
h_planchets: HashCode;
- // The array of blinded coins to be signed.
- h_coin_evs: HashCode[];
+ // The blinding seed that was provided. It will be NULL if
+ // no denominations of cipher type Clause-Schnorr were invovled
+ blinding_seed?: BlindingMasterSeed;
// The array of hashes of public key of denominations for the coins.
denom_pub_hashes: HashCode[];
@@ -5307,6 +5302,11 @@ regulatory compliance.
2 to wait for an AML investigation to be done,
and 3 to wait for the KYC status to be OK.
@since protocol **v21**.
+ :query min_rule=NUMBER: *Optional*.
+ Specifies the ``rule_num`` of the previous ``kyc-check``
+ already known to the client. When long-polling, the server
+ should always respond when it has a more recent rule.
+ @since protocol **v26**.
:query timeout_ms=NUMBER: *Optional.* If specified, the exchange will
wait up to ``timeout_ms`` milliseconds if the requirement continues
to be mandatory provisioning of KYC data by the client.
@@ -5368,6 +5368,12 @@ regulatory compliance.
// accounts without this flag being set!
aml_review: boolean;
+ // Monotonically increasing number identifying the decision.
+ // 0 if no decision was taken for this account. Useful for
+ // long-polling via ``min_rule`` to long-poll for any change
+ // to the rules or limits.
+ rule_gen: Integer;
+
// Access token needed to construct the ``/kyc-spa/``
// URL that the user should open in a browser to
// proceed with the KYC process (optional if the status
diff --git a/core/api-merchant.rst b/core/api-merchant.rst
@@ -2886,10 +2886,6 @@ Creating orders
// Tax receipt output.
type: "tax-receipt";
- // Total amount that will be on the tax receipt.
- // Optional, if missing the full amount will be on the receipt.
- amount?: Amount;
-
}
The following `MinimalInventoryProduct` can be provided if the parts of the
@@ -4832,8 +4828,7 @@ The contract terms must have the following structure:
donau_urls: string[];
// Total amount that will be on the tax receipt.
- // Optional, if missing the full amount will be on the receipt.
- amount?: Amount;
+ amount: Amount;
}
diff --git a/design-documents/060-clause-schnorr.rst b/design-documents/060-clause-schnorr.rst
@@ -0,0 +1,44 @@
+DD 60: TODO: Clause-Schnorr Signatures
+######################################
+
+Summary
+=======
+
+Certain denomination cipher types, such as Clause-Schnorr, require input values
+from the exchange-side as preparation for the blinding of the coins. See the
+Bachelor thesis of Gian Demarmels and Lucien Heuzeveldt,
+`Adding Schnorr’s Blind Signature in Taler <https://www.taler.net/papers/cs-thesis.pdf>`_,
+for details.
+
+Motivation
+==========
+
+TODO
+
+Requirements
+============
+
+TODO
+
+Proposed Solution
+=================
+
+TODO
+
+Definition of Done
+==================
+
+(Only applicable to design documents that describe a new feature. While the
+DoD is not satisfied yet, a user-facing feature **must** be behind a feature
+flag or dev-mode flag.)
+
+Alternatives
+============
+
+Drawbacks
+=========
+
+Discussion / Q&A
+================
+
+(This should be filled in with results from discussions on mailing lists / personal communication.)
diff --git a/design-documents/061-batched-withdraw.rst b/design-documents/061-batched-withdraw.rst
@@ -0,0 +1,48 @@
+DD 61: TODO: Batched Withdraw
+#############################
+
+Summary
+=======
+
+We propose to substitue the previous withdraw protocol with a variant that
+allows for batched withdrawal of multiple coins in only one (or two, in case of
+Clause-Schnorr) roundtrips.
+
+Motivation
+==========
+
+The original single-coin withdraw requires too many roundtrips, one for each
+coin, whenever a client wants to withdraw multiple coins.
+
+
+Requirements
+============
+
+TODO
+
+Proposed Solution
+=================
+
+TODO
+
+Definition of Done
+==================
+
+(Only applicable to design documents that describe a new feature. While the
+DoD is not satisfied yet, a user-facing feature **must** be behind a feature
+flag or dev-mode flag.)
+
+Alternatives
+============
+
+TODO
+
+Drawbacks
+=========
+
+TODO
+
+Discussion / Q&A
+================
+
+(This should be filled in with results from discussions on mailing lists / personal communication.)
diff --git a/design-documents/062-pq-refresh.rst b/design-documents/062-pq-refresh.rst
@@ -0,0 +1,290 @@
+DD 62: PQ Refresh Protocol
+##########################
+
+Summary
+=======
+This document specifies a change to GNU Taler's refresh protocol that provides
+post-quantum resistance through hash-based cryptography and deterministic
+signatures, eliminating reliance on Diffie-Hellman operations, for the key
+derivation for the fresh coin from a dirty coin.
+
+Motivation
+==========
+
+The current refresh protocol uses cryptographic primitives vulnerable to
+quantum attacks to derive the key material for a fresh coin from the key of the
+dirty coin. The rational for the elaborate derivation in first place is to
+ensure taxability: When original and new coins remain linked (by the owner of
+the original coin), passing coin outside the Taler protocols is discouraged.
+
+This redesign:
+
+1. Removes DH operations from refresh derivation
+2. Uses deterministic signatures for ownership proofs
+3. Derives key material from (unforgeable) signatures
+4. Maintains backward compatibility with other parts of the protocol stack
+
+Requirements
+============
+
+* PQ-resistant refresh without computational hardness assumptions
+* Preservation of unlinkability between old/new coins (except for coin owner)
+* Compatibility with existing denomination types
+* Minimal bandwidth/storage overhead
+
+Proposed Solution
+=================
+
+RefreshDerive Algorithm
+^^^^^^^^^^^^^^^^^^^^^^^^^
+
+The core mechanism uses two hash functions and deterministic signatures to
+derive the key material of a fresh coin from the old coin:
+
+.. sourcecode:: python
+
+ # Notation:
+ # r = random seed, cs = coin secret, Cp = coin public key
+ # pkD = denomination key
+
+ def RefreshDerive(r, cs, Cp, pkD):
+ t = Hash1a("Refresh", Cp, r)
+ s = SignDeterministic(cs, t)
+ x = Hash1b(s)
+ c2_s, C2_p = KeyGen(x)
+ b = Hash2(x)
+ m = Blind(C2_p, b, pkD)
+ return (s, c2_s, C2_p, m)
+
+
+Key Changes to the existing RefreshDerive:
+ 1. *Proof of ownership*: ``s`` proves ownership through signature, without DH
+ 2. *Key derivation*: ``x`` derived through hashing of the signature
+
+The hash functions ``Hash1x`` might be the same, but can be pair-wise
+different. However, the hash function ``Hash2`` must be different from
+all of the other.
+
+Protocol Modifications
+^^^^^^^^^^^^^^^^^^^^^^
+
+Here is a short description of the main steps, with only one fresh coin being
+requested. We will provide further details, once the related paper [1]_ is
+published.
+
+1. **Melting/Commit Phase**:
+
+ - Client chooses a master seed r and derives κ nonces r_1, ... r_κ.
+ - Client generates κ refresh blinded coin candidates m_1,... m_κ from them.
+ - Sends dirty coin, r, all m_i and new denom-info to the exchange, with
+ signature σ_c of the dirty coins' private key over the request.
+ - Exchange verifies the request.
+ - Exchange calculates h_m = H(m_1,...m_κ)
+ - Exchange chooses γ from 1...K and signs m_γ, resulting in σ_γ.
+ - Exchange persists h_m → (r, γ, m_γ, σ_γ, σ_c) and returns γ to the client.
+
+2. **Reveal Phase**:
+
+ - Client discloses together with h_m all except the γ-th random seeds r_i
+ and signatures s_i from the call to RefreshDerive.
+ - Exchange verifies signature s_i over Hash1a("Refresh", C_p, r_i).
+ - Exchange reconstructs the blinded coins m'_i.
+ - Exchange verifies h_m = H(m'_1, ..., m_γ, ... m'_κ) equality.
+ - Exchange returns σ_γ on success.
+
+It is worth noting that, in contrast to the existing refresh protocol, the
+client sends all κ tuples of m_i already in the commitment phase. This is
+necessary such that the exchange can sign the request with a valid denomination
+key *at the moment of melting*. This ensures idempotency of the melting/commit
+request and that caries over to the reveal phase.
+
+Note that for the Linking protocol, given the dirty coin's public key,
+the Exchange simply returns the master seed r and the dirty coins' signature
+σ_c over the original refresh request. The owner of the private key of the
+dirty coin can then replay the refresh protocol and can be sure that the master
+seed was of its own origin.
+
+
+Database Changes
+^^^^^^^^^^^^^^^^
+
+Not taking sharding and coinstraints into account, the table layout will look
+basically like this:
+
+.. table:: SQL table layout for refresh
+ :align: left
+
+ ============== ============ ================================================
+ Field Type Description
+ ============== ============ ================================================
+ refresh_id BIGINT autoincremented identity of the record
+ h_planchets BYTEA the value h_m above, serving as primary key
+ timestamp INT8 execution date of the refresh
+ amount taler_amount amount with fee of the refresh
+ old_coin_pub BYTEA the old coin's public key
+ old_coin_sig BYTEA old coin's signature over the refresh request
+ noreveal_index SMALLINT the γ for cut-and-choose, chosen by the exchange
+ h_blind_evs BYTEA[] the blinded coin evelopes, i.e. (many) m_γ above
+ r_nonce BYTEA the master seed for the refresh, the r above
+ denom_serials INT8[] the row ID's of the denominations in the DB
+ denom_sigs BYTEA[] the denom signatures for each h_blind_evs
+ ============== ============ ================================================
+
+
+API endpoints
+^^^^^^^^^^^^^^
+
+A new ``/melt`` request is needed, that takes the new `NewMeltRequest` as request
+body, see below.
+As in the existing melting/commit phase, it invalidates the coin and prepares
+for exchanging of fresh coins. Taler uses a global parameter ``kappa`` for the
+cut-and-choose component of the protocol, for which this request is the
+commitment. Thus, various arguments are given ``kappa``-times in this step.
+At present ``kappa`` is always 3.
+
+The base URL for ``/melt/``-requests may differ from the main base URL of the
+exchange. The exchange MUST return a 307 or 308 redirection to the correct base
+URL if this is the case.
+
+ :http:statuscode:`200 OK`:
+ The request was successful. The response body is `MeltResponse` in this case.
+ :http:statuscode:`403 Forbidden`:
+ One of the signatures is invalid.
+ :http:statuscode:`404 Not found`:
+ The exchange does not recognize the denomination key as belonging to the exchange,
+ or it has expired.
+ If the denomination key is unknown, the response will be
+ a `DenominationUnknownMessage`.
+ :http:statuscode:`409 Conflict`:
+ The operation is not allowed as the coin has insufficient
+ residual value, or because the same public key of the coin has been
+ previously used with a different denomination. Which case it is
+ can be decided by looking at the error code
+ (``TALER_EC_EXCHANGE_GENERIC_INSUFFICIENT_FUNDS`` or
+ ``TALER_EC_EXCHANGE_GENERIC_COIN_CONFLICTING_DENOMINATION_KEY``).
+ The response is `MeltForbiddenResponse` in both cases.
+ :http:statuscode:`410 Gone`:
+ The 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
+ `DenominationGoneMessage`. Clients must evaluate
+ the error code provided to understand which of the
+ cases this is and handle it accordingly.
+
+
+Wire Formats
+^^^^^^^^^^^^
+
+Modified melt request structure:
+
+.. ts:def:: NewMeltRequest
+
+ interface NewMeltRequest {
+ // The old coin's public key
+ old_coin_pub: CoinPublicKey;
+
+ // Hash of the denomination public key of the old coin, to determine total coin value.
+ old_denom_pub_h: HashCode;
+
+ // The hash of the age-commitment for the old coin. Only present
+ // if the denomination has support for age restriction.
+ old_age_commitment_h?: AgeCommitmentHash;
+
+ // Signature over the old `coin public key <eddsa-coin-pub>` by the denomination.
+ old_denom_sig: DenominationSignature;
+
+ // Amount of the value of the old coin that should be melted as part of
+ // this refresh operation, including melting fee.
+ value_with_fee: Amount;
+
+ // Master seed for the Clause-Schnorr R-value
+ // creation. Must match the /blinding-prepare request.
+ // Must not have been used in any prior melt request.
+ // Must be present if one of the fresh coin's
+ // denominations is of type Clause-Schnorr.
+ blinding_seed?: BlindingMasterSeed;
+
+ // Array of ``n`` new hash codes of denomination public keys
+ // for the new coins to order.
+ denoms_h: HashCode[];
+
+ // Seed from which the nonces for the n*κ coin candidates are derived
+ // from.
+ r_seed: HashCode;
+
+ // Array of ``n`` entries with ``kappa`` many blinded coin candidates,
+ // matching the respective entries in ``denoms_h``.
+ //
+ // Note: These are essentially the m_i values in the RefreshDerivePQ
+ // function.
+ coin_evs: CoinEnvelope[][kappa];
+
+ // Signature by the `coin <coin-priv>` over `TALER_NewMeltCommitmentPS`.
+ confirm_sig: CoinSignature;
+
+ }
+
+The new ``TALER_NewMeltCommitmentPS`` is defined as follows:
+
+.. _TALER_NewMeltCommitmentPS:
+.. sourcecode:: c
+
+ struct TALER_NewMeltCommitmentPS {
+ /**
+ * purpose.purpose = TALER_SIGNATURE_WALLET_COIN_MELT
+ */
+ struct GNUNET_CRYPTO_EccSignaturePurpose purpose;
+ struct TALER_CoinSpendPublicKeyP old_coin_public_key;
+ struct TALER_AgeCommitmentHash old_h_age_commitment;
+ struct TALER_AmountNBO value_with_fee;
+ /**
+ * rms value, or all zeros, if not applicable
+ */
+ struct TALER_RefreshMasterSecretP rms;
+ /**
+ * hash over all entries in denoms_h
+ */
+ struct GNUNET_HashCode h_denoms;
+ /**
+ * hash over all entries in coin_evs (aka m in RefreshDerivePQ),
+ * depths first
+ */
+ struct GNUNET_HashCode h_coin_evs;
+ /**
+ * The seed for the nonces
+ */
+ struct GNUNET_HashCode r_seed;
+ };
+
+TODO: definition of ``CoinSignature``
+
+.. ts:def:: CoinSignature
+
+ // TODO: this needs to be fully expanded into a new interface
+ type CoinSignature = string;
+
+
+
+Security Analysis
+=================
+
+TODO
+
+Drawbacks
+=========
+
+TODO
+
+Migration Strategy
+==================
+
+TODO
+
+Discussion/Q&A
+==============
+
+TODO
+
+
+References
+==========
+.. [1] Work by Jonathan Levin et al., TU Eindhoven. Reference be added here once published
diff --git a/design-documents/index.rst b/design-documents/index.rst
@@ -71,4 +71,7 @@ Design documents that start with "XX" are considered deprecated.
057-libeufin-bank-account-lockout.rst
058-ebics-tx-unique-id.rst
059-statistics
+ 060-clause-schnorr.rst
+ 061-batched-withdraw.rst
+ 062-pq-refresh.rst
999-template