taler-docs

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

080-short-wire-subject.rst (9711B)


      1 DD 80: Alternative wire transfer subjects
      2 #########################################
      3 
      4 :Design status: Accepted
      5 :Implementation status: Partial
      6 :DD shepherd: TBD
      7 :Historical contributors: Antoine A, Christian Grothoff
      8 :First published: 2026-01-13
      9 :Last substantive change: 2026-03-04
     10 :Implementation evidence: ``exchange`` (2026-02-28); the landed registration protocol differs from parts of this proposal
     11 :Normative references: ``core/api-bank-transfer.rst`` and ``core/bank-transfer/post-registration.rst``
     12 
     13 Summary
     14 =======
     15 
     16 Some mediums and clients do not support subjects large enough to contain an entire reserve public key,
     17 and filling in the subject manually is very error-prone.
     18 We need a way to generate new input methods for wire transfers that are linked to the metadata currenlty stored in the unstructured subject.
     19 We also need support for recurring transfers.
     20 
     21 Problem
     22 =======
     23 
     24 Swiss users are used to QR-code based payments with a numeric payment
     25 identifier for invoices. Some Swiss banking apps do not support the
     26 (long-ish) public key wire transfer subject we use today. Furthermore,
     27 banks in NZ use an even shorter encoding with 3 very short fields to
     28 encode the reasons for a wire transfer. Other countries may also have
     29 restrictions that are, well, unfortunate. Finally, for Depolymerization
     30 we used a hack to encode the reserve public key, but also could be
     31 more efficient if we could use less entropy.
     32 
     33 Handling small encoding space
     34 -----------------------------
     35 
     36 Using a very restricive alphabet like numeric and a very short wire subject
     37 length can leed us to quickly exaust most of the encoding space.  We thus need
     38 a way to recycle old short subjects.
     39 
     40 Parsing unstructured subjects
     41 -----------------------------
     42 
     43 We currently support two kinds of keys: reserve keys and KYC keys. We expect
     44 to need more key kind in the future, and using new crypto will make the
     45 encoded keys bigger.
     46 
     47 We quickly found that users inputing those keys had a tendency to add
     48 undesirable separators and worst, some client even add them automatically.
     49 Those users where than very frustrated by the experience and somtimes where
     50 completly prevented from using Taler.
     51 
     52 We also currently try to identify wire transfer subjects that are not
     53 well-formed and automatically bounce such wire transfers immediately. It
     54 would be great if we could make sure this happens more consistently
     55 (as right now small typos MAY still decode to a proper public key).
     56 
     57 Repeated wire transfers
     58 -----------------------
     59 
     60 Users may want to setup a periodic wire transfer into their wallet, which
     61 automatically tops-up their balance once a week or once a month. Here, we
     62 need to allow them to re-use the same wire transfer subject for a long
     63 time. However, the exchange logic requires a fresh reserve public key to
     64 be used each time.
     65 
     66 
     67 Proposed Solution
     68 =================
     69 
     70 .. note::
     71 
     72    The landed prepared-transfer protocol consolidates account allocation and
     73    authorization-key registration in ``POST /registration``.  It does not use
     74    the separate subject-generation/mapping endpoints or adaptive proof-of-work
     75    described in the historical proposal below.  The normative prepared-
     76    transfer API takes precedence.
     77 
     78 Wire transfer subject generation
     79 --------------------------------
     80 
     81 We need a new public endpoint where wallets can request a fresh wire transfer
     82 subject to be generated for them.  The result MUST be some JSON as the
     83 different wire methods will require one or more fields with different
     84 constraints (see NZ vs. CH). Some may be numbers, others may be strings, there
     85 may be checksum-constraints (or not), we simply cannot enumerate all
     86 possibilities.  So the new public API of the wire gateway (discoverable via
     87 the exchange) must have a plugin architecture and depending on the wire method
     88 generate a JSON object with fields specific to the wire method. If the
     89 underlying wire transfer subject format has no checksums, our wire
     90 transfer subject generator *should* add some (unless the entropy space is
     91 so tiny that even a small checksum is impractical).
     92 
     93 We also need to associate a fresh wire transfer subject with a public key at
     94 that point, so the client should POST its **registration** public key to the
     95 backend.
     96 
     97 The registration must have an **expiration**. How long can be configurable,
     98 the default should probably be at least a quarter. Usage of the registered
     99 wire transfer subject (by making such a wire transfer) should **extend** the
    100 expiration deadline. The current expiration should be **returned** by the
    101 service.  Wallets must communicate the expiration in the user interface,
    102 making it clear that the registration will lapse (unless used) and then funds
    103 may end up with a different user.
    104 
    105 The wire subject generation logic **should** avoid re-using wire transfer
    106 subjects, for example by (1) linearly going over the entropy space (modulo
    107 checksums and other constraints of the format), and (2) after cycling
    108 through it, skipping not only registered entries but also "recently expired"
    109 registrations (basically, keeping registrations around as blockers for a
    110 few days/weeks/months instead of immediately freeing the number).
    111 
    112 Finally, we protect the service against exhaustion attacks where an attacker
    113 drains our entropy space by sending too many registration requests. Here, an
    114 adaptive proof-of-work is the only reasonable solution.  Basically, as our
    115 available entropy space goes down, we exponentially increase the
    116 difficulty. The current difficulty could be exposed via ``/config``. The
    117 proof-of-work would be specific to the client's public key being
    118 registered. Unless the difficulty increased, the client is *allowed* to re-use
    119 the proof-of-work in subsequent registration requests (if the original once
    120 expired).  If a client's public key is already registered, we simply return
    121 the same wire transfer subject again (idempotency!).  However, once the
    122 registration expired, the client is likely to get a different wire transfer
    123 subject.
    124 
    125 For wire transfer methods without actual restrictions on the wire transfer
    126 subject, we could simply return the registration public key in a suitable
    127 field of the response, in extreme cases skip storing data in our database, and
    128 might even accept a zero-cost proof-of-work.
    129 
    130 Mapping to reserves
    131 -------------------
    132 
    133 Another endpoint allows wallets to map a registration public key to a unique
    134 reserve public key and a **transaction type** (like regular withdraw, KYC-auth,
    135 WAD, etc.).  For this endpoint, the wallet would have to sign using the
    136 registration key.  Each mapping is used at most once. If a client sends a new
    137 mapping before the old mapping has been used, the old mapping is simply
    138 discarded. Unused mappings expire when the registration expires.
    139 
    140 Handling incoming wire transfers
    141 --------------------------------
    142 
    143 If the incoming wire transfer subject has a wire transfer gateway defined
    144 checksum, it should be checked and possibly bounced if the subject is
    145 not well-formed.
    146 
    147 The wire transfer MUST also be bounced if the incomig wire transfer subject is
    148 not registered, or if the registration is expired, and if the wire transfer
    149 subject is not recognized as a registration public key (if the wire method has
    150 no entropy constraints and we skipped writing registrations to the database).
    151 For backwards-compatibility, reserve public keys (possibly with "KYC"-flag)
    152 should also be supported initially and not be bounced.
    153 
    154 If a reserve public key and transaction type are already registered
    155 for the registration public key, the exchange is informed. Otherwise,
    156 the wire transfer is put in a "hold" state until either it passes some
    157 configurable **hold delay** or such a registration is received.
    158 
    159 Subject derivation
    160 ------------------
    161 
    162 The subject derivation must be deterministic and use the entire coding space.
    163 
    164 We will continue to support the current encoding for simple cases.
    165 
    166 All subject derivation starts by making a hash of the key using SHA 256.
    167 
    168 Then the hash bits are encoded differently for each subject format:
    169 
    170 Swiss QR-bill
    171 ^^^^^^^^^^^^^
    172 
    173 Treat the whole hash as a big integer then modulo by 10 power 26.
    174 Encode the remainder into a string and add the 27th checksum character according to QR-bill spec.
    175 
    176 Auditor
    177 -------
    178 
    179 By running the subject derivation logic itself and using the new authorization public key and signature fields in the wire gateway API, the auditor can match corresponding transfers.
    180 
    181 Taler Prepared Transfer HTTP API
    182 ---------------------------------
    183 
    184 See the :ref:`Taler Prepared Transfer <taler-prepared-transfer-http-api>` documentation.
    185 
    186 Test Plan
    187 =========
    188 
    189 
    190 Definition of Done
    191 ==================
    192 
    193 Only the prepared-transfer API and exchange registration client have been
    194 established from current-tree evidence; the remaining deployment and UI items
    195 are intentionally unchecked.
    196 
    197 * [ ] New API supported by all wire gateways
    198 * [x] Prepared-transfer API specifies Swiss QR Bill wire transfer subjects
    199 * [x] Exchange registration client supports the wire transfer API
    200 * [ ] Wallets support registration
    201 * [ ] Wallets have UI where the user can specify "periodic"
    202   wire transfers where the wallets periodically try to
    203   map new reserve public keys to an existing registration
    204 * [ ] *Optional*: remove legacy mode?
    205 
    206 
    207 Alternatives
    208 ============
    209 
    210 The mapping of registration key to reserve key could also specify the
    211 amount. That may help map multiple wire transfers to the "right" key, but
    212 would create problems for the UX if the user got the amount wrong.
    213 
    214 
    215 Drawbacks
    216 =========
    217 
    218 Theoretically, transfering money using a long-expired wire transfer
    219 subject may send money to a different wallet. This seems to be
    220 unavoidable with low-entropy wire transfer subjects.
    221 
    222 
    223 
    224 Discussion / Q&A
    225 ================