taler-docs

Documentation for GNU Taler components, APIs and protocols
Log | Files | Refs | README | LICENSE

commit beccb8dc7add5c843adf1b2c2fd2c2bb86e01068
parent 6ceaac25ed1f770fa5a670532b5333d606b23609
Author: Christian Grothoff <grothoff@gnunet.org>
Date:   Wed, 14 Jan 2026 01:53:20 +0100

elaborate on DD800 ideas

Diffstat:
Mdesign-documents/080-short-wire-subject.rst | 198+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--------------------
1 file changed, 149 insertions(+), 49 deletions(-)

diff --git a/design-documents/080-short-wire-subject.rst b/design-documents/080-short-wire-subject.rst @@ -10,66 +10,167 @@ We need to add an endpoint to link a reserve public key to shorter sequences tha Problem ======= -User-provided config vs backend config --------------------------------------- - -Short wire subjects will be generated based on a size and an alphabet. -The supported alphabet would be: - -* numeric 0-9 -* uppercase_alphanumeric A-Z0-9 -* alphanumeric a-zA-Z0-9 - -We could add other alphabets with symbols or lowercase only, but from experience, the most restrictive system that only accepts small wire transfer subject are also very restrictive about the accepted characters. - -Then remains the question of who will decide those parameters: the user or the backend administrator. -I would be simpler to let the administrator configure this, but this mean than a user with a special, more restrictive client won’t be -able to use our system. -Maybe the backend provides a default, and the user can override? +Swiss users are used to QR-code based payments with a numeric payment +identifier for invoices. Some Swiss banking apps do not support the +(long-ish) public key wire transfer subject we use today. Furthermore, +banks in NZ use an even shorter encoding with 3 very short fields to +encode the reasons for a wire transfer. Other countries may also have +restrictions that are, well, unfortunate. Finally, for Depolymerization +we used a hack to encode the reserve public key, but also could be +more efficient if we could use less entropy. Handling small encoding space ----------------------------- -Using a very restricive alphabet like numeric and a very short wire subject lenght can leed us to quickly exaust most of the encoding space. -We might need a way to recycle old short subjects. - -Parsing unstructure subject ---------------------------- - -We currently support two kinds of keys: reserve keys and KYC keys. We expect to need more key kind in the future, and using new crypto will make the encoded keys bigger. - -A reserve key looks like this: 00Q979QSMJ29S7BJT3DDAVC5A0DR5Z05B7N0QT1RCBQ8FXJPZ6RG +Using a very restricive alphabet like numeric and a very short wire subject +length can leed us to quickly exaust most of the encoding space. We thus need +a way to recycle old short subjects. -And a KYC key like this: KYC:NDDCAM9XN4HJZFTBD8V6FNE2FJE8GY734PJ5AGQMY06C8D4HB3Z0 - -We quickly found that users inputing those keys had a tendency to add undesirable separators and worst, some client even add them automatically. -Those users where than very frustrated by the experience and somtimes where completly prevented from using Taler. -We therefore came up with a solution to parse unstructured subjects like this one: - -Taler KIC:NDDCAM9XN4HJZFTBD8V6FNE2FJE8G Y734PJ5AGQMY06C8D4HB3Z0 - -We first remove all non-alphanumeric ASCII characters to get some chunks: - -Taler KYC NDDCAM9XN4HJZFTBD8V6FNE2FJE8G Y734PJ5AGQMY06C8D4HB3Z0 - -We then try to assemble chunks until they form a potential valid key: - -TalerKYC TalerKYCNDDCAM9XN4HJZFTBD8V6FNE2FJE8G TalerKYCNDDCAM9XN4HJZFTBD8V6FNE2FJE8GY734PJ5AGQMY06C8D4HB3Z0 KYCNDDCAM9XN4HJZFTBD8V6FNE2FJE8G KYCNDDCAM9XN4HJZFTBD8V6FNE2FJE8GY734PJ5AGQMY06C8D4HB3Z0 +Parsing unstructured subjects +----------------------------- -Then we decode the key and check if they are valid public key. +We currently support two kinds of keys: reserve keys and KYC keys. We expect +to need more key kind in the future, and using new crypto will make the +encoded keys bigger. -There is also a bit of logic to handle cases where many valid keys are found to prefer the one that looks the most legit (KYC prefixed, uppercase only, etc). +We quickly found that users inputing those keys had a tendency to add +undesirable separators and worst, some client even add them automatically. +Those users where than very frustrated by the experience and somtimes where +completly prevented from using Taler. -Decoding the key and checking it is expensive, but this whole algo stayed fast because we knew the possible sizes of the encoded keys, either 52 chars for a reserve key or 52 + 3 for a KYC prefixed key. -Therefore, most of the assemble chunks where skipped, and we only rarely had to run the expensive decoding logic more than once. +We also currently try to identify wire transfer subjects that are not +well-formed and automatically bounce such wire transfers immediately. It +would be great if we could make sure this happens more consistently +(as right now small typos MAY still decode to a proper public key). -Short subject will be of variable sizes, either because of user config or because of backend configuration changes. We need to chose if and how we want handle this with unstructured subjects. +Repeated wire transfers +----------------------- -We can either expect the full subject to be the short one. In that case, it’s, simple, we just remove al non ASCII alphanumeric and make a single search in the database. +Users may want to setup a periodic wire transfer into their wallet, which +automatically tops-up their balance once a week or once a month. Here, we +need to allow them to re-use the same wire transfer subject for a long +time. However, the exchange logic requires a fresh reserve public key to +be used each time. -Or we reuse the chunk logic and match many potential keys in a single DB query. The problem with this is that this can be expensive as the number of possible chunk is exponential and a bad user could create a very specific subject that create many combination. Proposed Solution ================= -TODO -\ No newline at end of file +Wire transfer subject generation +-------------------------------- + +We need a new public endpoint where wallets can request a fresh wire transfer +subject to be generated for them. The result MUST be some JSON as the +different wire methods will require one or more fields with different +constraints (see NZ vs. CH). Some may be numbers, others may be strings, there +may be checksum-constraints (or not), we simply cannot enumerate all +possibilities. So the new public API of the wire gateway (discoverable via +the exchange) must have a plugin architecture and depending on the wire method +generate a JSON object with fields specific to the wire method. If the +underlying wire transfer subject format has no checksums, our wire +transfer subject generator *should* add some (unless the entropy space is +so tiny that even a small checksum is impractical). + +We also need to associate a fresh wire transfer subject with a public key at +that point, so the client should POST its **registration** public key to the +backend. + +The registration must have an **expiration**. How long can be configurable, +the default should probably be at least a quarter. Usage of the registered +wire transfer subject (by making such a wire transfer) should **extend** the +expiration deadline. The current expiration should be **returned** by the +service. Wallets must communicate the expiration in the user interface, +making it clear that the registration will lapse (unless used) and then funds +may end up with a different user. + +The wire subject generation logic **should** avoid re-using wire transfer +subjects, for example by (1) linearly going over the entropy space (modulo +checksums and other constraints of the format), and (2) after cycling +through it, skipping not only registered entries but also "recently expired" +registrations (basically, keeping registrations around as blockers for a +few days/weeks/months instead of immediately freeing the number). + +Finally, we protect the service against exhaustion attacks where an attacker +drains our entropy space by sending too many registration requests. Here, an +adaptive proof-of-work is the only reasonable solution. Basically, as our +available entropy space goes down, we exponentially increase the +difficulty. The current difficulty could be exposed via ``/config``. The +proof-of-work would be specific to the client's public key being +registered. Unless the difficulty increased, the client is *allowed* to re-use +the proof-of-work in subsequent registration requests (if the original once +expired). If a client's public key is already registered, we simply return +the same wire transfer subject again (idempotency!). However, once the +registration expired, the client is likely to get a different wire transfer +subject. + +For wire transfer methods without actual restrictions on the wire transfer +subject, we could simply return the registration public key in a suitable +field of the response, in extreme cases skip storing data in our database, and +might even accept a zero-cost proof-of-work. + +Mapping to reserves +------------------- + +Another endpoint allows wallets to map a registration public key to a unique +reserve public key and a **transaction type** (like regular withdraw, KYC-auth, +WAD, etc.). For this endpoint, the wallet would have to sign using the +registration key. Each mapping is used at most once. If a client sends a new +mapping before the old mapping has been used, the old mapping is simply +discarded. Unused mappings expire when the registration expires. + +Handling incoming wire transfers +-------------------------------- + +If the incoming wire transfer subject has a wire transfer gateway defined +checksum, it should be checked and possibly bounced if the subject is +not well-formed. + +The wire transfer MUST also be bounced if the incomig wire transfer subject is +not registered, or if the registration is expired, and if the wire transfer +subject is not recognized as a registration public key (if the wire method has +no entropy constraints and we skipped writing registrations to the database). +For backwards-compatibility, reserve public keys (possibly with "KYC"-flag) +should also be supported initially and not be bounced. + +If a reserve public key and transaction type are already registered +for the registration public key, the exchange is informed. Otherwise, +the wire transfer is put in a "hold" state until either it passes some +configurable **hold delay** or such a registration is received. + + +Test Plan +========= + + +Definition of Done +================== + +* New endpoints supported by all wire gateways +* Support for Swiss-specific wire transfer subjects +* Exchange points wallets/merchants to wire gateway APIs +* Wallets support registration +* Wallets have UI where the user can specify "periodic" + wire transfers where the wallets periodically try to + map new reserve public keys to an existing registration +* *Optional*: remove legacy mode? + + +Alternatives +============ + +The mapping of registration key to reserve key could also specify the +amount. That may help map multiple wire transfers to the "right" key, but +would create problems for the UX if the user got the amount wrong. + + +Drawbacks +========= + +Theoretically, transfering money using a long-expired wire transfer +subject may send money to a different wallet. This seems to be +unavoidable with low-entropy wire transfer subjects. + + + +Discussion / Q&A +================