draft-grothoff-donau-01.xml (38641B)
1 <?xml version="1.0" encoding="UTF-8"?> 2 <rfc xmlns:xi="http://www.w3.org/2001/XInclude" 3 category="info" docName="draft-grothoff-donau-01" 4 ipr="trust200902" submissionType="independent" version="3"> 5 <!-- SEE ALSO: https://docs.taler.net/core/taler-uri.html --> 6 7 <!-- FIXME ipr is copied from lsd0001, need to be updated --> 8 <front xmlns=""> 9 <title abbrev="The 'donau' URI scheme"> 10 The 'donau' URI scheme for validation of Donau donation statements. 11 </title> 12 13 <author fullname="Christian Grothoff" initials="C.G." surname="Grothoff"> 14 <organization>Bern University of Applied Sciences</organization> 15 <address> 16 <postal> 17 <street>Höheweg 80</street> 18 <city>Biel/Bienne</city> 19 <code>2501</code> 20 <country>CH</country> 21 </postal> 22 <email>christian.grothoff@bfh.ch</email> 23 </address> 24 </author> 25 26 <author fullname="Emmanuel Benoist" initials="E.B." surname="Benoist"> 27 <organization>Bern University of Applied Sciences</organization> 28 <address> 29 <postal> 30 <street>Höheweg 80</street> 31 <city>Biel/Bienne</city> 32 <code>2501</code> 33 <country>CH</country> 34 </postal> 35 <email>emmanuel.benoist@bfh.ch</email> 36 </address> 37 </author> 38 39 40 <author fullname="Bohdan Potuzhnyi" initials="B.P." surname="Potuzhnyi"> 41 <organization>Bern University of Applied Sciences</organization> 42 <address> 43 <postal> 44 <street>Höheweg 80</street> 45 <city>Biel/Bienne</city> 46 <code>2501</code> 47 <country>CH</country> 48 </postal> 49 <email>bohdan.potuzhnyi@bfh.ch</email> 50 </address> 51 </author> 52 53 54 <author fullname="Florian Dold" initials="F.D." surname="Dold"> 55 <organization>Taler Systems AG</organization> 56 <address> 57 <postal> 58 <street>7, rue de Mondorf</street> 59 <city>Erpeldange</city> 60 <code>5421</code> 61 <country>LU</country> 62 </postal> 63 <email>dold@taler.net</email> 64 </address> 65 </author> 66 67 68 <date day="2" month="November" year="2025" /> 69 70 <!-- Meta-data Declarations --> 71 <area>General</area> 72 <workgroup>Independent Stream</workgroup> 73 <keyword>taxation</keyword> 74 75 <abstract> 76 77 <t> 78 This document defines the 'donau' Uniform Resource Identifier (URI) scheme 79 for triggering interactions with a validator for Donau donation 80 statements. 81 </t> 82 83 <t> 84 This URI scheme allows applications to trigger interactions 85 with a Donau validator. A Donau validator is typically run by 86 a tax authority to validate tax records from citizens that 87 made donations to a charity that supports the Donau protocol. 88 The Donau validator will receive 'donau' URIs representing the 89 sum of donations a taxpayer made to recognized charities over 90 a year. Donors would submit 'donau' URLs (or QR codes with 91 'donau' URLs) to tax authorities to have their donations 92 recognized by the tax authority as tax-deductible 93 expenditures. The application logic to verify the validity of 94 the donation is triggered by 'donau' URIs. The validator 95 application would then typically confirm to the tax official 96 the validity of the signature encoded in the URI and show the 97 total amount donated as well as the taxpayer identification 98 number and the year of the donation. Multiple URIs could be 99 submitted per donor, and the application can correctly 100 determine which submissions are cumulative and which ones are 101 redundant. 102 </t> 103 104 <t> 105 This specification only covers the syntax of the 'donau' URI 106 scheme and excludes details on the protocol(s) that would 107 allow taxpayers to donate to recognized charities to obtain 108 these suitable signed donation statements. While a 109 privacy-preserving protocol to obtain such statements exists 110 within the context of the GNU Taler protocol suite, other 111 protocols could be developed in the future and still yield 112 compatible 'donau' URIs as the URI scheme is reasonably generic. 113 </t> 114 <t> 115 The validation tool will be registered for all donau:// URIs. 116 Since each taxation authority will typically use a different 117 domain, it will not be feasible to encode all the 118 domains of tax authorities servers inside the validation tool. 119 Hence a new URI scheme is needed that will trigger the validation 120 tool for any domain name. 121 </t> 122 </abstract> 123 124 </front> 125 126 <middle xmlns=""> 127 128 <section anchor="introduction"> 129 <name>Introduction</name> 130 <t> 131 This document defines the 'donau' Uniform Resource Identifier (URI) 132 <xref target="RFC3986" /> scheme for triggering interactions with 133 Donau validators. 134 </t> 135 136 <section> 137 <name>Objective</name> 138 <t> 139 A 'donau' URI always instructs a Donau validator to perform the 140 validation of a Donau donation statement. 141 A 'donau' URI consists of the reference to the authority 142 that signed the statement, an identifier for the specific taxpayer, 143 the year of the donation, a salt and optional parameters. 144 Optional parameters include the total amount donated by the 145 taxpayer and the signature of the Donau donation statement. 146 </t> 147 <t> 148 This specification is based on the Bachelor Thesis of 149 Casaburi and Matya <xref target="BaThesis" /> presenting the 150 solution and the first implementation of a Donau system. 151 </t> 152 </section> 153 154 155 <section> 156 <name>Requirements Language</name> 157 <t> 158 The keywords "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", 159 "SHOULD", "SHOULD NOT", "RECOMMENDED", "NOT RECOMMENDED", "MAY", and 160 "OPTIONAL" in this document are to be interpreted as described in BCP 14 161 <xref target="RFC2119"/> <xref target="RFC8174"/> when, and only when, 162 they appear in all capitals, as shown here. 163 </t> 164 </section> 165 166 </section> 167 168 <section anchor="syntax"> 169 <name>Syntax of a 'donau' URI</name> 170 <t> 171 This document uses the Augmented Backus-Naur Form (ABNF) of <xref target="RFC5234"/>. 172 </t> 173 <figure> 174 <artwork type="abnf"><![CDATA[ 175 ; Scheme and high-level structure 176 scheme = "donau" / "DONAU" / "donau+http" / "DONAU+HTTP" 177 donau-URI = scheme "://" base "?" year-param "&" 178 taxid-param "&" salt-param 179 ("&" total-param "&" sig-param)? 180 181 ; The base is the HTTP(S) origin plus optional path segments that 182 ; identify the Donau REST API deployment. Everything before the last 183 ; three path segments (year, taxid-enc, salt) is part of the base. 184 base = 1*( ALPHA / DIGIT / "-" / "." / ":" / "/" / "_" ) 185 186 year-param = [ "year" / "YEAR" ] "=" year 187 188 tax-id-param = [ "id" / "ID" ] "=" tax-id-enc 189 190 salt-param = [ "salt" / "SALT" ] "=" salt 191 192 total-param = [ "total" / "TOTAL" ] "=" amount 193 194 signature-param = [ "sig" / "SIG" ] "=" algo ":" signature 195 196 ; Path parameters 197 year = DIGIT DIGIT DIGIT DIGIT 198 199 ; The taxid-enc is the percent-encoding (RFC 3986) of the UTF-8 200 ; taxpayer identifier string. See semantics for decoding rules. 201 taxid-enc = 1*( unreserved / pct-encoded ) 202 pct-encoded = "%" HEXDIG HEXDIG 203 unreserved = ALPHA / DIGIT / "-" / "." / "_" / "~" 204 205 ; Salt remains an opaque string for the URI and is interpreted by 206 ; the Donau system. (See semantics.) 207 salt = 1*( ALPHA / DIGIT ) 208 209 ; Query parameters and signature encoding 210 amount = currency ":" unit [ "." fraction ] 211 currency = 1*ALPHA 212 unit = 1*( DIGIT ) 213 fraction = 1*( DIGIT ) 214 algo = "ED25519" 215 signature = 1*( ALPHA / DIGIT ) 216 ]]> 217 </artwork> 218 </figure> 219 </section> 220 221 <section anchor="semantics"> 222 <name>Semantics</name> 223 <t> 224 Even if RFC3986 <xref target="RFC3986"/> explicitly writes that scheme names 225 are case-insensitive, lower and upper case variations are presented here to 226 emphasize this possibility. The applications encoding URI in a QR-code can 227 benefit from the possibility to encode the URI using only uppercase letters 228 which should result in a more compact encoding. 229 </t> 230 <t> 231 The base of a Donau URI refers to the base URL of the Donau REST API. 232 It consists of the network location (host name or IP address) and <bcp14>MAY</bcp14> include 233 additional path segments (for example, <tt>https://admin.ch/taxes/donau/</tt>) 234 mapping to the Donau deployment behind reverse proxies. Validators <bcp14>MUST NOT</bcp14> 235 assume a specific domain naming convention or pattern 236 (such as <tt>donau.example</tt>) and 237 <bcp14>MUST</bcp14> accept bases with or without additional path components. 238 </t> 239 <t> 240 The year of a Donau URI refers to the year when the donations 241 have been done. 242 </t> 243 <t> 244 The taxid of a Donau URI refers to the taxid of the person that 245 did the donations and asks for their Donau donation statement to 246 be verified. The format of the taxid is specific for each tax authority. 247 The taxid is conveyed in the URI as a percent-encoded query parameter as 248 per <xref target="RFC3986"/>. Implementations <bcp14>MUST</bcp14> decode <tt>taxid-enc</tt> 249 by applying percent-decoding to obtain the exact UTF-8 bytes of the tax identifier 250 before any processing. In particular, the character '/' <bcp14>MUST</bcp14> be percent-encoded 251 as <tt>%2F</tt> if present in a tax identifier. 252 </t> 253 <t> 254 255 The salt of a Donau URI refers to information used by a 256 wallet application to generate the Donau donation statement. 257 This salt is wallet-specific. As taxpayers <bcp14>MAY</bcp14> 258 use multiple wallets, tax authorities <bcp14>SHOULD</bcp14> 259 allowing a taxpayer to supply multiple Donau 260 donation statements for the same year. If the salts 261 are different, these should be treated as 262 cumulative by the validator application. The salt 263 <bcp14>SHOULD</bcp14> also used to obfuscate the taxpayer ID 264 in the donation protocol. 265 </t> 266 <t> 267 The total follows the syntax from <xref target="RFC8905"/> and 268 represents the total amount donated in this year by the given 269 taxpayer with the given salt. Thus, given multiple 'donau' URIs 270 with the same salt, the maximum total amount should be used, while 271 the total amounts from 'donau' URIs with different salts should be 272 added. 273 </t> 274 <t> 275 Finally, <tt>algo</tt> specifies the specific signature algorithm 276 used; for now, 277 only ED25519 (see <xref target="RFC8032" />) is supported. 278 The signature using the specified algorithm <bcp14>MUST</bcp14> be 279 made over the information above (see <xref target="signature"/>) 280 and <bcp14>MUST</bcp14> be encoded using the Base 32 U Crockford encoding 281 scheme <xref target="base32-U-crockford"/>. 282 </t> 283 <t> 284 The default operation of applications that invoke a URI with the 285 Donau scheme <bcp14>MUST</bcp14> be to launch a Donau validator (if 286 available). If no Donau validator is available, an application 287 <bcp14>SHOULD</bcp14> show a QR code with the content of the URI. 288 If multiple 289 Donau validators are registered, the user <bcp14>SHOULD</bcp14> be able to choose 290 which application to launch. This allows users with multiple 291 validators to choose which validator to perform the operation 292 with. 293 </t> 294 <!--<t> 295 An application <bcp14>SHOULD</bcp14> allow dereferencing a "donau://" URI even 296 if the action of that URI is not registered in the "Donau URI 297 Actions" sub-registry. 298 </t>--> 299 <t> 300 Validators <bcp14>MUST</bcp14> use HTTP over TLS when processing a "<tt>donau</tt>" URI. 301 Validators <bcp14>MUST</bcp14> use HTTP without TLS when processing a "<tt>donau+http</tt>" URI. 302 The base origin <bcp14>SHOULD</bcp14> be shown to the 303 user to indicate which authority issued the proof of donation. 304 Alternatively, specific validation apps <bcp14>MAY</bcp14> only accept 'donau' 305 URLs from a specific set of hard-coded authorities and simply display 306 an error message when given 'donau' URLs from other authorities. 307 </t> 308 </section> 309 310 <section anchor="examples"> 311 <name>Examples</name> 312 <figure> 313 <artwork><![CDATA[ 314 ; Minimal example with a simple base and simple taxid 315 donau://example.com/ 316 ?year=2025&id=7560001010000& 317 salt=1234& 318 total=EUR:15& 319 sig=ED25519: 320 H9PM3BW3P8MEKB34GZ0G1F7JSNVX7B8AHXRFFMS37QZM7TXZ5MWPXTEDZZGN1 321 QRB1AFPKNCFXJB39NJHP3BAFGCZSCXHEYPHA1YJY28 322 323 ; Example with percent-encoded taxid containing '/' 324 donau://donau.test.taler.net/ 325 ?year=2025&id=123%2F456%2F789& 326 salt=1234& 327 total=TESTKUDOS:1& 328 sig=ED25519: 329 B14WGS43FFPEB8JMSR6W1H8M6KH9AV33JFH376R6PM2MNH4GR24FP1C93C4ZPDG2 330 1W5WY4SASZQ4CRS427F4WJZJFZMQ5Y4HZNXGY30 331 332 ; Example with a base URL that includes path components 333 donau://admin.ch/taxes/donau/ 334 ?year=2025&id=7560001010000& 335 salt=1234& 336 total=EUR:15& 337 sig=ED25519: 338 H9PM3BW3P8MEKB34GZ0G1F7JSNVX7B8AHXRFFMS37QZM7TXZ5MWPXTEDZZGN1 339 QRB1AFPKNCFXJB39NJHP3BAFGCZSCXHEYPHA1YJY28 340 ]]> 341 </artwork> 342 </figure> 343 </section> 344 345 <section anchor="verification"> 346 <name>Verification of a Donau URI</name> 347 <t> 348 The verification requires the Donau verification application to test 349 if a given taxpayer is entitled to a tax reduction. 350 For doing this, the Donau verification application must 351 verify that the Donau URI corresponds to a valid Donau donation 352 statement. The Donau verification application <bcp14>MUST</bcp14> verify the 353 validity of the donation statement. There are two possibilities: 354 signature and total are available, or at least one is not available. 355 </t> 356 <t> 357 If signature and total are available, then the verification 358 application <bcp14>MUST</bcp14> verify 359 that the signature is valid for the server key (see <xref 360 target="get-server-keys"/> to get the key). 361 </t> 362 <t> 363 If either or both are missing, the application <bcp14>MUST</bcp14> download them from 364 the get donation statement endpoint <xref target="get-donation-statement"/>. 365 </t> 366 367 </section> 368 <section anchor="get-server-keys"> 369 <name>Obtaining Donau Server Public Keys</name> 370 <t> 371 The verification app <bcp14>MUST</bcp14> obtain the signing public key 372 corresponding to the base for the given year. 373 The key <bcp14>MAY</bcp14> be retrieved from a 374 cache. If no key for this base and this year is available in the 375 cache, the verification app <bcp14>MUST</bcp14> download the key from the 376 base. The Donau server <bcp14>MUST</bcp14> provide the key at the /keys 377 endpoint. If the key is not available, no verification can take place 378 and the validator <bcp14>MUST</bcp14> return an appropriate error. 379 380 The verification app <bcp14>SHOULD</bcp14> cache downloaded signing 381 public keys for the current year. 382 </t> 383 <ul> 384 <li>Endpoint: /keys</li> 385 <li>Method: GET</li> 386 <li>Syntax: base/keys</li> 387 <li>Syntax response: defined hereunder</li> 388 <li>References: [this.I-D]</li> 389 </ul> 390 391 <t> 392 Each of the "<tt>signkeys</tt>" is valid between "<tt>stamp_start</tt>" and 393 "<tt>stamp_expire</tt>" and the public "<tt>key</tt>" returned is encoded using Base 32 394 U Crockford encoding <xref target="base32-U-crockford"/>. 395 </t> 396 397 <sourcecode> 398 <![CDATA[ 399 ; Core JSON tokens (simplified; assumes standard JSON dialect) 400 JSONString = DQUOTE *(%x20-21 / %x23-5B / 401 %x5D-10FFFF / "\" EscapedChar) DQUOTE 402 UCrockford = *( ALPHA32 / "-" ) 403 ALPHA32 = DIGIT / LETTER 404 DIGIT = %x30-39 ; 0-9 405 LETTER = %x41-48 / %x4A-4E / %x50-5A / %x61-68 / %x6A-6E / %x70-7A 406 JSONUCrockfordString = DQUOTE UCrockford DQUOTE 407 EscapedChar = %x22 / %x5C / %x2F / %x62 / %x66 / 408 %x6E / %x72 / %x74 / "u" 4HEXDIG 409 JSONNumber = [ "-" ] 1DIGIT *( DIGIT ) [ "." 1DIGIT *( DIGIT ) ] 410 [ ( "e" / "E" ) [ "+" / "-" ] 1DIGIT *( DIGIT ) ] 411 JSONBool = "true" / "false" 412 JSONNull = "null" 413 JSONArray = "[" [ JSONException *( "," JSONException ) ] "]" 414 JSONObject = "{" [ JSONMember *( "," JSONMember ) ] "}" 415 JSONMember = JSONString ":" JSONException 416 JSONException = JSONString / JSONNumber / JSONObject / 417 JSONArray / JSONBool / JSONNull 418 419 ; Specific DonauKeysResponse structure 420 DonauKeysResponse = "{" 421 JSONMemberSep 422 "}" 423 JSONMemberSep = version , domain , base_url , currency , 424 currency_fraction_digits , donation_units , signkeys 425 426 version = DQUOTE "version" DQUOTE ":" JSONString 427 domain = DQUOTE "domain" DQUOTE ":" JSONString 428 base_url = DQUOTE "base_url" DQUOTE ":" JSONString 429 currency = DQUOTE "currency" DQUOTE ":" JSONString 430 currency_fraction_digits = DQUOTE "currency_fraction_digits" 431 DQUOTE ":" JSONNumber 432 EDDSAPubKey = JSONUCrockfordString 433 SignKey = DQUOTE "key" DQUOTE ":" EDDSAPubKey 434 donation_units = DQUOTE "donation_units" DQUOTE ":" "[" 435 DonationUnitKeyGroup *( 436 "," DonationUnitKeyGroup ) "]" 437 signkeys = DQUOTE "signkeys" DQUOTE ":" "[" SignKey 438 *( "," SignKey ) "]" 439 440 DonationUnitKeyGroup = "{" cipher_field "," value_field "," 441 donation_units_array "}" 442 cipher_field = DQUOTE "cipher" DQUOTE ":" ( 443 DQUOTE "RSA" DQUOTE / DQUOTE "CS" DQUOTE ) 444 value_field = DQUOTE "value" DQUOTE ":" JSONNumber 445 donation_units_array = DQUOTE "donation_units" DQUOTE ":" "[" 446 DUNK_UNIT_KEY *( 447 "," DUNK_UNIT_KEY ) "]" 448 449 ; donation unit entries differ depending on cipher 450 DUNK_UNIT_KEY = "{" base_fields "," key_specific "}" 451 base_fields = DQUOTE "year" DQUOTE ":" JSONNumber 452 [ "," DQUOTE "lost" DQUOTE ":" JSONBool ] 453 key_specific = ( DQUOTE "rsa_pub" DQUOTE ":" JSONObject ) / 454 ( DQUOTE "cs_pub" DQUOTE ":" JSONString ) 455 456 SignKey = "{" DQUOTE "key" DQUOTE ":" JSONObject "," 457 DQUOTE "year" DQUOTE ":" JSONNumber "}" 458 ]]> 459 </sourcecode> 460 461 <t>Example, a response to a GET request to the <tt>/keys</tt> endpoint.</t> 462 <sourcecode> 463 <![CDATA[ 464 { "signkeys": 465 [ 466 { 467 "stamp_start": {"ts_s": 42 }, 468 "stamp_expire": {"ts_s": 43 }, 469 "key": "XXXXXXXXXXXXXXXX" 470 } 471 ] 472 } 473 ]]> 474 </sourcecode> 475 </section> 476 477 478 <section anchor="get-donation-statement"> 479 <name>Donation Statement Retrieval</name> 480 <t> 481 If the Donau URI does not contain the total or the signature, the 482 verification app <bcp14>MUST</bcp14> download them from the <tt>/donation-statement</tt> 483 endpoint of the base.<br/> 484 485 The verification app <bcp14>MUST</bcp14> compute the hash of the donor 486 taxpayer ID <tt>hash-donor-id</tt> using SHA-512 <xref target="RFC6234"/> 487 over the exact UTF-8 bytes of the taxpayer ID string, followed by a single 488 NUL byte (0x00), followed by the salt string, followed by a final NUL byte (0x00): 489 <tt>hash-donor-id = SHA-512(taxid || 0x00 || salt || 0x00)</tt>. 490 Here, <tt>taxid</tt> is the UTF-8 string obtained by percent-decoding the <tt>taxid-enc</tt> path segment. 491 The verification app <bcp14>MUST</bcp14> contact the 492 base at the endpoint <tt>/donation-statement</tt> with the year and <tt>hash-donor-id</tt>. 493 494 The hash of the donor taxpayer ID <tt>hash-donor-id</tt> <bcp14>MUST</bcp14> be encoded 495 using Base 32 U Crockford 496 encoding <xref target="base32-U-crockford"/>. 497 </t> 498 499 <ul> 500 <li>Endpoint: /donation-statement</li> 501 <li>Method: GET</li> 502 <li>Syntax: base/donation-statement/{year}/{hash-donor-id}</li> 503 <li>References: [this.I-D]</li> 504 </ul> 505 506 <t> 507 Servers implementing the donation-statement endpoint 508 <bcp14>MUST</bcp14> respect the 509 following syntax; all three fields (<tt>total-field</tt>, <tt>sig-field</tt>, <tt>pub-field</tt>) <bcp14>MUST</bcp14> be included. 510 511 The total amount is a string formed first of the currency (in capital 512 letters) then ":" and then the value (can be an integer or a decimal 513 number). 514 </t> 515 516 <sourcecode> 517 <![CDATA[ 518 json-object = "{" ws field-list ws "}" 519 520 field-list = field *(ws "," ws field) 521 field = total-field / sig-field / pub-field 522 523 ; Allow any order of the three fields 524 total-field = DQUOTE "total" DQUOTE ws ":" ws 525 DQUOTE currency ":" value DQUOTE 526 sig-field = DQUOTE "donation_statement_sig" DQUOTE ws ":" 527 ws DQUOTE signature DQUOTE 528 pub-field = DQUOTE "donau_pub" DQUOTE ws ":" ws 529 DQUOTE signature DQUOTE ; same format as signature 530 531 currency = 1*(%x41-5A) ; A-Z uppercase letters 532 value = int / decimal 533 int = ["-"] 1*DIGIT 534 decimal = ["-"] 1*DIGIT "." 1*DIGIT 535 536 signature = 1*(ALPHA / DIGIT / "=") 537 538 ; Common tokens 539 ws = *WSP 540 DQUOTE = %x22 ; " 541 WSP = %x20 / %x09 542 DIGIT = %x30-39 543 ALPHA = %x41-5A / %x61-7A 544 ]]> 545 </sourcecode> 546 547 <t>Example of an element of USD 100.00 :</t> 548 <sourcecode> 549 <![CDATA[ 550 { 551 "total": "USD:100", 552 "donation_statement_sig": "SIGNATURE", 553 "donau_pub": "EDDSA_PUBLIC_KEY" 554 } 555 ]]> 556 </sourcecode> 557 </section> 558 559 560 <section anchor="signature-total-available"> 561 <name>Verification if Signature and Total are Available</name> 562 <t> 563 The verification app <bcp14>MUST</bcp14> verify that the signature corresponds to 564 the claimed values. 565 566 If the information is not in the URI, the verification app <bcp14>MUST</bcp14> 567 download the total and the signature from the 568 base using the GET <tt>/donation-statement</tt> endpoint <xref 569 target="get-donation-statement"/>. Otherwise, it <bcp14>SHOULD</bcp14> use the 570 value given in the URI. 571 572 The verification of the signature is done using EdDSA as 573 specified in <xref target="RFC8032" />. 574 575 The verification <bcp14>MAY</bcp14> be done with the following instructions. 576 The signed data is the concatenation of the following fields 577 in network byte order (big-endian): 578 </t> 579 580 <ul> 581 <li>size (4 bytes): 32-bit unsigned integer with the total length of the signed data in bytes.</li> 582 <li>purpose (4 bytes): 32-bit unsigned integer with the constant value <tt>1500</tt>.</li> 583 <li>total value (8 bytes): integer part as an unsigned 64-bit integer.</li> 584 <li>total fraction (4 bytes): fractional part as an unsigned 32-bit integer in units of 1/100000000.</li> 585 <li>currency (12 bytes): ASCII string, left-aligned with zero-padding on the right to 12 bytes.</li> 586 <li>hash of donor taxpayer ID (64 bytes): <tt>hash-donor-id = SHA-512( UTF-8(taxid) || 0x00 || UTF-8(salt) || 0x00 )</tt>.</li> 587 <li>year (4 bytes): 32-bit unsigned integer (the donation year).</li> 588 </ul> 589 </section> 590 591 592 <section anchor="signature"> 593 <name>Creating Donation Statement Signatures</name> 594 <t> 595 The server signing the donation statement <bcp14>MUST</bcp14> use the Sign(d,message) procedure implemented as defined in <xref target="RFC8032" />. 596 </t> 597 <t> 598 The signature over the public key covers a 32-bit pseudo header 599 conceptually prefixed to the donation data fields. 600 The wire format is illustrated 601 in <xref target="figure_donausigwithpseudo"/>. 602 </t> 603 <figure anchor="figure_donausigwithpseudo"> 604 <name>The Format for Creating Donation Statement Signatures</name> 605 <artwork name="" type="" alt=""> 606 0 8 16 24 32 40 48 56 607 +-----+-----+-----+-----+-----+-----+-----+-----+ 608 | SIZE | PURPOSE (1500) | 609 +-----+-----+-----+-----+-----+-----+-----+-----+ 610 | TOTAL value | 611 +-----+-----+-----+-----+-----+-----+-----+-----+ 612 | TOTAL fraction | CURRENCY | 613 +-----+-----+-----+-----+ + 614 | | 615 +-----+-----+-----+-----+-----+-----+-----+-----+ 616 | SHA512 of the donor ID | 617 / / 618 / / 619 +-----+-----+-----+-----+-----+-----+-----+-----+ 620 | YEAR | 621 +-----+-----+-----+-----+ 622 </artwork> 623 </figure> 624 <dl newline="false"> 625 <dt>SIZE:</dt> 626 <dd> 627 A 32-bit value containing the length of the signed data in bytes 628 in network byte order. 629 </dd> 630 <dt>PURPOSE:</dt> 631 <dd> 632 A 32-bit signature purpose flag in network byte order. The value of this 633 field <bcp14>MUST</bcp14> be 1500. It defines the context in which 634 the signature is created so that it cannot be reused in other parts 635 of the protocol that might include possible future extensions. 636 The value of this field corresponds to an entry in the 637 GANA "GNUnet Signature Purposes" registry <xref target="GANA"/>. 638 </dd> 639 <dt>TOTAL value:</dt> 640 <dd> 641 The integer part of the total value. 642 Unsigned integer containing the integer part of the value for the total. 643 It is represented using a 64 bit value (in big endian). 644 </dd> 645 <dt>TOTAL fraction:</dt> 646 <dd> 647 The fractional part of the total value is represented by an 648 unsigned integer on 32 bits (also in big endian notation). 649 It represents the fractional part of the value in 1/100000000th of the base unit. 650 </dd> 651 <dt>TOTAL currency</dt> 652 <dd> 653 A string representing the currency. ASCII, left-aligned and zero-padded to exactly 12 bytes. 654 </dd> 655 <dt>HASH:</dt> 656 <dd>The SHA512 hash code for the donor ID.</dd> 657 <dt>YEAR:</dt> 658 <dd>The year on a 32 bit unsigned integer in big endian.</dd> 659 </dl> 660 </section> 661 662 <section anchor="signature-verification"> 663 <name>Validating Donation Statement Signatures</name> 664 <t> 665 The signature verification step is taking the data presented in the 666 figure <xref target="figure_donausigwithpseudo" /> as input. 667 The signature <bcp14>MUST</bcp14> be verified using the EdDSA scheme described in 668 <xref target="RFC8032" /> the procedure is 669 <tt>Verify(zk,message,signature)</tt>. 670 Public key and signature, which are 671 encoded in Base 32 U Crockford in the URL, 672 <bcp14>MUST</bcp14> first be decoded to obtain the 673 respective binary value. 674 </t> 675 <t> 676 The Sign(d,message) and Verify(zk,message,signature) procedures <bcp14>MUST</bcp14> 677 be implemented as defined in <xref target="RFC8032" />. 678 </t> 679 </section> 680 681 682 <section anchor="base32-U-crockford"> 683 <name>Base 32 Representation of Binary Data</name> 684 <t> 685 All binary data <bcp14>MUST</bcp14> be encoded to be transmitted. For encoding, one 686 <bcp14>MUST</bcp14> use the Base32 U Crockford encoding. This is a variation of the 687 base32 encoding <xref target ="RFC4648" />. This encoding is presented 688 in detail in the appendix of the RFC for GNU Name System <xref target="RFC9498" /> 689 </t> 690 <t> 691 The encoding works similarly to the standard, but uses another Base 32 692 Alphabet. The new alphabet is given in the Table <xref target="figure_base32_encoding" />, below. 693 </t> 694 695 <figure anchor="figure_base32_encoding"> 696 <name>The Base 32 Encoding Alphabet.</name> 697 <artwork name="" type="" align="left" alt="table where value between 0 and 9 are encoded with the character corresponding to the number. Then between 10 and 31, we have all the letters expect I, L, O, U that could be misleading (OCR may not recognize them properly). Padding is the char ="><![CDATA[ 698 Value Encoding Value Encoding Value Encoding Value Encoding 699 0 0 9 9 18 J 27 V 700 1 1 10 A 19 K 28 W 701 2 2 11 B 20 M 29 X 702 3 3 12 C 21 N 30 Y 703 4 4 13 D 22 P 31 Z 704 5 5 14 E 23 Q 705 6 6 15 F 24 R (pad) = 706 7 7 16 G 25 S 707 8 8 17 H 26 T 708 709 ]]> 710 </artwork> 711 </figure> 712 713 <t> 714 To prevent optical character reading (OCR) problems, a system decoding 715 binary data encoded with base 32 U Crockford <bcp14>MUST</bcp14> 716 accept the codes presented in the Table <xref target="figure_base32_decoding"/>, below. 717 System reading a <tt>U</tt> <bcp14>MUST</bcp14> evaluate it as a <tt>V</tt>. 718 </t> 719 720 <figure anchor="figure_base32_decoding"> 721 <name>The Base 32 Decoding Alphabet.</name> 722 <artwork name="" type="" align="left" alt=""><![CDATA[ 723 Value Encoding Value Encoding Value Encoding Value Encoding 724 0 0 9 9 18 J|j 27 V|v|u|U 725 1 1|i|I|l|L 10 A|a 19 K|k 28 W|w 726 2 2 11 B|b 20 M|m 29 X|x 727 3 3 12 C|c 21 N|n 30 Y|y 728 4 4 13 D|d 22 P|p 31 Z|z 729 5 5 14 E|e 23 Q|q 730 6 6 15 F|f 24 R|r (pad) = 731 7 7 16 G|g 25 S|s 732 8 8 17 H|h 26 T|t 733 ]]></artwork> 734 </figure> 735 736 737 </section> 738 739 <section anchor="security"> 740 <name>Security Considerations</name> 741 <t> 742 Donau validators <bcp14>SHOULD</bcp14> support 743 "<tt>donau+http://</tt>"-URIs only when run in developer or debug mode 744 as otherwise the integrity and authenticity of the public key 745 cannot be assured. 746 </t> 747 <t> 748 Running "<tt>donau+http://</tt>"-URIs on a production server 749 <bcp14>MUST NOT</bcp14> be permitted, since it would be a security issue. 750 This scheme is intended only for testing purposes, 751 for instance on <tt>localhost</tt>. 752 </t> 753 <t> 754 Validator applications <bcp14>MUST</bcp14> include protections 755 against repeated validations of the same donation statement 756 with the same salt and year. Specifically, when summing up 757 multiple donation statements for the same taxpayer and 758 tax year, the <bcp14>MUST</bcp14> keep enough state to add 759 up the maximum total amounts per salt if multiple donation 760 statements are submitted with the same salt. 761 </t> 762 </section> 763 764 765 <section anchor="iana"> 766 <name slugifiedName="name-iana-considerations">IANA Considerations</name> 767 <t> 768 IANA maintains the "Uniform Resource Identifier (URI) Schemes" 769 registry that contains an entry for the 'donau' URI scheme. IANA is 770 requested to update that entry to reference this document when 771 published as an RFC. 772 </t> 773 <dl indent="3" newline="false" spacing="normal"> 774 <dt>Scheme name:</dt> 775 <dd> donau</dd> 776 <dt>Status:</dt> 777 <dd> provisional</dd> 778 <dt>URI scheme syntax:</dt> 779 <dd>See <xref target="syntax" format="default" sectionFormat="of" derivedContent="Section 3"/> of [This.I-D].</dd> 780 <dt>URI scheme semantics:</dt> 781 <dd>See <xref target="semantics" format="default" sectionFormat="of" derivedContent="Section 4"/> of [This.I-D].</dd> 782 <dt>Applications/protocols that use this scheme name:</dt> 783 <dd> GNU Taler</dd> 784 <dt>Contact:</dt> 785 <dd> 786 <t><contact fullname="Christian Grothoff"/> <grothoff@gnu.org></t> 787 </dd> 788 <dt>Change controller:</dt> 789 <dd> 790 <t><contact fullname="Christian Grothoff"/> <grothoff@gnu.org></t> 791 </dd> 792 <dt>References:</dt> 793 <dd> See <xref target="refs" format="default" sectionFormat="of" derivedContent="Section 13"/> of [This.I-D].</dd> 794 </dl> 795 </section> 796 797 798 </middle> 799 800 <back xmlns=""> 801 802 803 804 805 <references anchor="refs"> 806 <name>Normative References</name> 807 808 <xi:include href="https://bib.ietf.org/public/rfc/bibxml/reference.RFC.2119.xml"/> 809 810 <xi:include href="https://bib.ietf.org/public/rfc/bibxml/reference.RFC.3986.xml"/> 811 812 <xi:include href="https://bib.ietf.org/public/rfc/bibxml/reference.RFC.8174.xml"/> 813 814 <xi:include href="https://bib.ietf.org/public/rfc/bibxml/reference.RFC.5234.xml"/> 815 816 <xi:include href="https://bib.ietf.org/public/rfc/bibxml/reference.RFC.6234.xml"/> 817 818 <xi:include href="https://bib.ietf.org/public/rfc/bibxml/reference.RFC.8032.xml"/> 819 820 <xi:include href="https://bib.ietf.org/public/rfc/bibxml/reference.RFC.9498.xml"/> 821 822 <xi:include href="https://bib.ietf.org/public/rfc/bibxml/reference.RFC.8905.xml"/> 823 824 825 </references> 826 827 <references> 828 <name>Informational References</name> 829 830 <xi:include href="https://bib.ietf.org/public/rfc/bibxml/reference.RFC.4648.xml"/> 831 832 833 <reference anchor="GANA" target="https://gana.gnunet.org/"> 834 <front> 835 <title>GNUnet Assigned Numbers Authority (GANA)</title> 836 <author><organization>GNUnet e.V.</organization> 837 </author> 838 <date month="April" year="2020" /> 839 </front> 840 </reference> 841 842 <reference anchor="BaThesis" target="https://www.taler.net/papers/donau-thesis.pdf"> 843 <front> 844 <title>Tax-deductable Privacy-Preserving Donations</title> 845 <author initials="J.C." surname="Casaburi" fullname="Johannes Casaburi"> 846 <organization>Bern University of Applied Science, Bachelor Thesis</organization> 847 </author> 848 <author initials="L.M." surname="Matya" fullname="Lukas Matya"> 849 <organization>Bern University of Applied Science, Bachelor Thesis</organization> 850 </author> 851 </front> 852 </reference> 853 </references> 854 855 <section anchor="appendix-test-vectors"> 856 <name>Appendix. Test Vector: Verify from URI</name> 857 <t> 858 This appendix shows how to verify a donation statement starting from a 859 received URI. Public key is fetched from the Donau base. 860 </t> 861 862 <figure> 863 <artwork><![CDATA[ 864 Example URI: 865 donau://donau.test.taler.net/?year=2025&id=123%2F456%2F789& 866 salt=AWNFDRFT0WX45W4Y32A9DJA03S1EF66GFQZ9EV5EF9JTHWZ37WR0& 867 total=TESTKUDOS:1& 868 sig=ED25519: 869 B14WGS43FFPEB8JMSR6W1H8M6KH9AV33JFH376R6PM2MNH4GR24FP1C93C4ZPDG21 870 W5WY4SASZQ4CRS427F4WJZJFZMQ5Y4HZNXGY30 871 872 Extracted fields: 873 - base: donau.test.taler.net 874 - year: 2025 875 - taxid: 123%2F456%2F789 876 - taxid (decoded): 123/456/789 877 - salt: AWNFDRFT0WX45W4Y32A9DJA03S1EF66GFQZ9EV5EF9JTHWZ37WR0 878 - total: TESTKUDOS:1 879 - signature: ED25519:B14WGS43FFPEB8JMSR6W1H8M6KH9AV33JFH376R6PM2MNH4 880 GR24FP1C93C4ZPDG21W5WY4SASZQ4CRS427F4WJZJFZMQ5Y4HZNXGY30 881 882 Fetched public key for year 2025 from https://donau.test.taler.net/keys: 883 - pub: 2FRN2CAK9DMDWE157W6HY97RAVSP0ZCCC08X9N6JD2MK7413XXZG 884 ]]></artwork> 885 </figure> 886 887 <t>Verification steps:</t> 888 <ol> 889 <li>Input (URI):<br/> 890 <tt>donau://donau.test.taler.net/?year=2025&id=123%2F456%2F789& 891 salt=AWNFDRFT0WX45W4Y32A9DJA03S1EF66GFQZ9EV5EF9JTHWZ37WR0& 892 total=TESTKUDOS:1& 893 sig=ED25519:B14WGS43FFPEB8JMSR6W1H8M6KH9AV33JFH376R6PM2MNH4GR24FP1C93C4ZPDG21 894 W5WY4SASZQ4CRS427F4WJZJFZMQ5Y4HZNXGY30</tt></li> 895 <li>Parse fields:<br/> 896 - base: <tt>donau.test.taler.net</tt><br/> 897 - year: <tt>2025</tt> (4 digits)<br/> 898 - taxid-enc: <tt>123%2F456%2F789</tt><br/> 899 - taxid (UTF-8, percent-decoded, no trimming): <tt>123/456/789</tt><br/> 900 - salt (ASCII): <tt>AWNFDRFT0WX45W4Y32A9DJA03S1EF66GFQZ9EV5EF9JTHWZ37WR0</tt><br/> 901 - total (amount string): <tt>TESTKUDOS:1</tt><br/> 902 - sig (Crockford Base32, algorithm ED25519): <tt>B14WGS...XGY30</tt></li> 903 <li>Public signing key (Crockford Base32) (from <tt>/keys</tt>):<br/> 904 <tt>2FRN2CAK9DMDWE157W6HY97RAVSP0ZCCC08X9N6JD2MK7413XXZG</tt></li> 905 <li>Hash of the donor taxpayer ID <tt>hash-donor-id</tt> = <tt>SHA-512( UTF-8(taxid) || 0x00 || UTF-8(salt) || 0x00 )</tt>:<br/> 906 - length: 64 bytes<br/> 907 - hex:<br/> 908 <tt>4aaa1e16fc5be44842b863b1f17da39296ca7b3529a720e11aba9c8bd729f7a 1e2bb0b9a39c02d271da5dd15aea66ce95be78bcaf380de19a0bdbcd8a7938f1b</tt><br/> 909 - Crockford Base32 (for HTTP endpoints):<br/> 910 <tt>9AN1W5QWBFJ4GGNRCERZ2ZD3JABCMYSN56KJ1R8TQAE8QNS9YYGY5ERBK 8WW0B973PJXT5DEMSPEJPZ7HF5F706Y36GBVF6RMY9RY6R</tt></li> 911 <li>Total amount encoding (<tt>TALER_AmountNBO</tt>):<br/> 912 - currency (12 bytes): <tt>"TESTKUDOS"</tt> then <tt>0x00</tt> x 3<br/> 913 - value (uint64 BE): <tt>1</tt> -> <tt>0x0000000000000001</tt><br/> 914 - fraction (uint32 BE): <tt>0</tt> -> <tt>0x00000000</tt></li> 915 <li>Signed message <tt>M</tt> layout (network byte order, total 100 bytes):<br/> 916 - [0000..0003] 4 bytes <tt>size</tt>: <tt>0x00000064</tt><br/> 917 - [0004..0007] 4 bytes <tt>purpose</tt>: <tt>0x000005DC</tt> (1500)<br/> 918 - [0008..0015] 8 bytes <tt>amount.value</tt>: <tt>0x0000000000000001</tt><br/> 919 - [0016..0019] 4 bytes <tt>amount.fraction</tt>: <tt>0x00000000</tt><br/> 920 - [0020..0031] 12 bytes <tt>amount.currency</tt>: <tt>54 45 53 54 4b 55 44 4f 53 00 00 00</tt> ("TESTKUDOS\x00\x00\x00")<br/> 921 - [0032..0095] 64 bytes <tt>i.hash</tt>: hash of donor taxpayer ID <tt>hash-donor-id</tt><br/> 922 - [0096..0099] 4 bytes <tt>year</tt>: <tt>0x000007E9</tt> (2025)</li> 923 <li>Message <tt>M</tt> (hex, 100 bytes):<br/> 924 <tt>00000064 000005dc 0000000000000001 00000000 544553544b55444f53000000 4aaa1e16fc5be44842b863b1f17da39296ca7b3529a720e11aba9c8bd729f7a1e2bb0b 9a39c02d271da5dd15aea66ce95be78bcaf380de19a0bdbcd8a7938f1b 000007e9</tt></li> 925 <li>Signature (ED25519, Crockford Base32 -> bytes):<br/> 926 - length: 64 bytes<br/> 927 - R (first 32 bytes, hex):<br/> 928 <tt>5849c864837bece5a254ce0dc0c51434e2956c6393e2339b06b5054ac490c088</tt><br/> 929 - S (last 32 bytes, hex):<br/> 930 <tt>fb05891b09fb36020f0bcf132acfee46632411de4e4bf27fe972f891fd7b0f0c</tt></li> 931 <li>Public key (Ed25519, Crockford Base32 -> bytes):<br/> 932 - length: 32 bytes<br/> 933 - hex:<br/> 934 <tt>13f15131534b68de38253f0d1f24f856f3607d8c6011d4d4d268a9339023ef7f</tt></li> 935 <li>Verification (expected): call <tt>crypto_sign_verify_detached(sig, M, 100, pubkey)</tt>. The result <bcp14>MUST</bcp14> indicate a valid signature for this vector.</li> 936 <li>Negative check (optional): flip one bit of <tt>M</tt> or <tt>sig</tt> and repeat; verification <bcp14>MUST</bcp14> fail.</li> 937 </ol> 938 </section> 939 940 <section numbered="false"> 941 <name>Acknowledgements</name> 942 <t> 943 The authors thank Ted Hardie for his comments on an earlier version of the draft. 944 This work was funded in part by the European Commission through the 945 Horizon Europe program under project number 101135475 (TALER). It also 946 has received funding from the Swiss State Secretariat for Education, 947 Research and Innovation (SERI). 948 </t> 949 </section> 950 951 <!-- Change Log 952 v00 2025-10-17 CG Initial version 953 v01 2025-10-21 EB Including first reviews (motivations + change in URI structure) 954 --> 955 </back> 956 </rfc>