lsd0013

LSD0013: The donau:// scheme
Log | Files | Refs

draft-grothoff-donau-02.xml (37798B)


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