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 ================