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