commit c294f6951df01d5e6b244e7a3568b421ddaccf2b
parent 00ebedbf33bc122d72ca3557cfbe318a810e09a1
Author: Christian Grothoff <christian@grothoff.org>
Date: Thu, 6 Nov 2025 17:50:19 +0100
release v02
Diffstat:
2 files changed, 948 insertions(+), 2 deletions(-)
diff --git a/draft-donau.xml b/draft-donau.xml
@@ -4,7 +4,6 @@
ipr="trust200902" submissionType="independent" version="3">
<!-- SEE ALSO: https://docs.taler.net/core/taler-uri.html -->
-<!-- FIXME ipr is copied from lsd0001, need to be updated -->
<front xmlns="">
<title abbrev="The 'donau' URI scheme">
The 'donau' URI scheme for validation of donation statements.
@@ -942,7 +941,7 @@ W5WY4SASZQ4CRS427F4WJZJFZMQ5Y4HZNXGY30</tt></li>
<!-- Change Log
v00 2025-10-17 CG Initial version
v01 2025-10-21 EB Including first reviews (motivations + change in URI structure)
-v02 2025-11-05 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
+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
-->
</back>
</rfc>
diff --git a/draft-grothoff-donau-02.xml b/draft-grothoff-donau-02.xml
@@ -0,0 +1,947 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<rfc xmlns:xi="http://www.w3.org/2001/XInclude"
+ category="info" docName="draft-grothoff-donau-02"
+ ipr="trust200902" submissionType="independent" version="3">
+<!-- SEE ALSO: https://docs.taler.net/core/taler-uri.html -->
+
+ <front xmlns="">
+ <title abbrev="The 'donau' URI scheme">
+ The 'donau' URI scheme for validation of donation statements.
+ </title>
+
+ <author fullname="Christian Grothoff" initials="C." surname="Grothoff">
+ <organization>Bern University of Applied Sciences</organization>
+ <address>
+ <postal>
+ <street>Höheweg 80</street>
+ <city>Biel/Bienne</city>
+ <code>2501</code>
+ <country>CH</country>
+ </postal>
+ <email>christian.grothoff@bfh.ch</email>
+ </address>
+ </author>
+
+ <author fullname="Emmanuel Benoist" initials="E." surname="Benoist">
+ <organization>Bern University of Applied Sciences</organization>
+ <address>
+ <postal>
+ <street>Höheweg 80</street>
+ <city>Biel/Bienne</city>
+ <code>2501</code>
+ <country>CH</country>
+ </postal>
+ <email>emmanuel.benoist@bfh.ch</email>
+ </address>
+ </author>
+
+
+ <author fullname="Bohdan Potuzhnyi" initials="B." surname="Potuzhnyi">
+ <organization>Bern University of Applied Sciences</organization>
+ <address>
+ <postal>
+ <street>Höheweg 80</street>
+ <city>Biel/Bienne</city>
+ <code>2501</code>
+ <country>CH</country>
+ </postal>
+ <email>bohdan.potuzhnyi@bfh.ch</email>
+ </address>
+ </author>
+
+
+ <author fullname="Florian Dold" initials="F." surname="Dold">
+ <organization>Taler Systems AG</organization>
+ <address>
+ <postal>
+ <street>7, rue de Mondorf</street>
+ <city>Erpeldange</city>
+ <code>5421</code>
+ <country>LU</country>
+ </postal>
+ <email>dold@taler.net</email>
+ </address>
+ </author>
+
+
+ <date day="2" month="November" year="2025" />
+
+ <!-- Meta-data Declarations -->
+ <area>General</area>
+ <workgroup>Independent Stream</workgroup>
+ <keyword>taxation</keyword>
+
+ <abstract>
+
+ <t>
+ This document defines the 'donau' Uniform Resource Identifier (URI) scheme
+ for triggering interactions with a validator for Donau donation
+ statements.
+ </t>
+
+ <t>
+ This URI scheme allows applications to trigger interactions
+ with a Donau validator. A Donau validator is typically run by
+ a tax authority to validate tax records from citizens that
+ made donations to a charity that supports the Donau protocol.
+ The Donau validator will receive 'donau' URIs representing the
+ sum of donations a taxpayer made to recognized charities over
+ a year. Donors would submit 'donau' URLs (or QR codes with
+ 'donau' URLs) to tax authorities to have their donations
+ recognized by the tax authority as tax-deductible
+ expenditures. The application logic to verify the validity of
+ the donation is triggered by 'donau' URIs. The validator
+ application would then typically confirm to the tax official
+ the validity of the signature encoded in the URI and show the
+ total amount donated as well as the taxpayer identification
+ number and the year of the donation. Multiple URIs could be
+ submitted per donor, and the application can correctly
+ determine which submissions are cumulative and which ones are
+ redundant.
+ </t>
+
+ <t>
+ This specification only covers the syntax of the 'donau' URI
+ scheme and excludes details on the protocol(s) that would
+ allow taxpayers to donate to recognized charities to obtain
+ these suitable signed donation statements. While a
+ privacy-preserving protocol to obtain such statements exists
+ within the context of the GNU Taler protocol suite, other
+ protocols could be developed in the future and still yield
+ compatible 'donau' URIs as the URI scheme is reasonably generic.
+ </t>
+ <t>
+ The validation tool will be registered for all donau:// URIs.
+ Since each taxation authority will typically use a different
+ domain, it will not be feasible to encode all the
+ domains of tax authorities servers inside the validation tool.
+ Hence a new URI scheme is needed that will trigger the validation
+ tool for any domain name.
+ </t>
+ </abstract>
+
+ </front>
+
+<middle xmlns="">
+
+<section anchor="introduction">
+ <name>Introduction</name>
+<t>
+ This document defines the 'donau' Uniform Resource Identifier (URI)
+ <xref target="RFC3986" /> scheme for triggering interactions with
+ Donau validators.
+</t>
+
+<section>
+ <name>Objective</name>
+ <t>
+ A 'donau' URI always instructs a Donau validator to perform the
+ validation of a Donau donation statement.
+ A 'donau' URI consists of the reference to the authority
+ that signed the statement, an identifier for the specific taxpayer,
+ the year of the donation, a salt and optional parameters.
+ Optional parameters include the total amount donated by the
+ taxpayer and the signature of the Donau donation statement.
+ </t>
+ <t>
+ This specification is based on the Bachelor Thesis of
+ Casaburi and Matya <xref target="BaThesis" /> presenting the
+ solution and the first implementation of a Donau system.
+ </t>
+</section>
+
+
+<section>
+ <name>Requirements Language</name>
+ <t>
+ The keywords "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT",
+ "SHOULD", "SHOULD NOT", "RECOMMENDED", "NOT RECOMMENDED", "MAY", and
+ "OPTIONAL" in this document are to be interpreted as described in BCP 14
+ <xref target="RFC2119"/> <xref target="RFC8174"/> when, and only when,
+ they appear in all capitals, as shown here.
+ </t>
+</section>
+
+</section>
+
+<section anchor="syntax">
+ <name>Syntax of a 'donau' URI</name>
+ <t>
+ This document uses the Augmented Backus-Naur Form (ABNF) of <xref target="RFC5234"/>.
+ </t>
+ <figure>
+ <artwork type="abnf"><![CDATA[
+ ; Scheme and high-level structure
+ scheme = "donau"
+ donau-URI = scheme "://" base "?" year-param "&"
+ taxid-param "&" salt-param
+ ("&" total-param "&" sig-param)?
+
+ ; The base is the HTTP(S) origin plus optional path segments that
+ ; identify the Donau REST API deployment. Everything before the last
+ ; three path segments (year, taxid-enc, salt) is part of the base.
+ base = 1*( ALPHA / DIGIT / "-" / "." / ":" / "/" / "_" )
+
+ year-param = [ "year" ] "=" year
+
+ tax-id-param = [ "id" ] "=" tax-id-enc
+
+ salt-param = [ "salt" ] "=" salt
+
+ total-param = [ "total" ] "=" amount
+
+ signature-param = [ "sig" ] "=" algo ":" signature
+
+ ; Path parameters
+ year = DIGIT DIGIT DIGIT DIGIT
+
+ ; The taxid-enc is the percent-encoding (RFC 3986) of the UTF-8
+ ; taxpayer identifier string. See semantics for decoding rules.
+ taxid-enc = 1*( unreserved / pct-encoded )
+ pct-encoded = "%" HEXDIG HEXDIG
+ unreserved = ALPHA / DIGIT / "-" / "." / "_" / "~"
+
+ ; Salt remains an opaque string for the URI and is interpreted by
+ ; the Donau system. (See semantics.)
+ salt = 1*( ALPHA / DIGIT )
+
+ ; Query parameters and signature encoding
+ amount = currency ":" unit [ "." fraction ]
+ currency = 1*ALPHA
+ unit = 1*( DIGIT )
+ fraction = 1*( DIGIT )
+ algo = "ED25519"
+ signature = 1*( ALPHA / DIGIT )
+]]>
+ </artwork>
+ </figure>
+</section>
+
+<section anchor="semantics">
+ <name>Semantics</name>
+ <t>
+ The base of a Donau URI refers to the base URL of the Donau REST API.
+ It consists of the network location (host name or IP address) and <bcp14>MAY</bcp14> include
+ additional path segments (for example, <tt>https://admin.ch/taxes/donau/</tt>)
+ mapping to the Donau deployment behind reverse proxies. Validators <bcp14>MUST NOT</bcp14>
+ assume a specific domain naming convention or pattern
+ (such as <tt>donau.example</tt>) and
+ <bcp14>MUST</bcp14> accept bases with or without additional path components.
+ </t>
+ <t>
+ The year of a Donau URI refers to the year when the donations
+ have been done.
+ </t>
+ <t>
+ The taxid of a Donau URI refers to the taxid of the person that
+ did the donations and asks for their Donau donation statement to
+ be verified. The format of the taxid is specific for each tax authority.
+ The taxid is conveyed in the URI as a percent-encoded query parameter as
+ per <xref target="RFC3986"/>. Implementations <bcp14>MUST</bcp14> decode <tt>taxid-enc</tt>
+ by applying percent-decoding to obtain the exact UTF-8 bytes of the tax identifier
+ before any processing. In particular, the character '/' <bcp14>MUST</bcp14> be percent-encoded
+ as <tt>%2F</tt> if present in a tax identifier.
+ </t>
+ <t>
+
+ The salt of a Donau URI refers to information used by a
+ wallet application to generate the Donau donation statement.
+ This salt is wallet-specific. As taxpayers <bcp14>MAY</bcp14>
+ use multiple wallets, tax authorities <bcp14>SHOULD</bcp14>
+ allowing a taxpayer to supply multiple Donau
+ donation statements for the same year. If the salts
+ are different, these should be treated as
+ cumulative by the validator application. The salt
+ <bcp14>SHOULD</bcp14> also used to obfuscate the taxpayer ID
+ in the donation protocol.
+ </t>
+ <t>
+ The total follows the syntax from <xref target="RFC8905"/> and
+ represents the total amount donated in this year by the given
+ taxpayer with the given salt. Thus, given multiple 'donau' URIs
+ with the same salt, the maximum total amount should be used, while
+ the total amounts from 'donau' URIs with different salts should be
+ added.
+ </t>
+ <t>
+ Finally, <tt>algo</tt> specifies the specific signature algorithm
+ used; for now,
+ only ED25519 (see <xref target="RFC8032" />) is supported.
+ The signature using the specified algorithm <bcp14>MUST</bcp14> be
+ made over the information above (see <xref target="signature"/>)
+ and <bcp14>MUST</bcp14> be encoded using the Base 32 U Crockford encoding
+ scheme <xref target="base32-U-crockford"/>.
+ </t>
+ <t>
+ The default operation of applications that invoke a URI with the
+ Donau scheme <bcp14>MUST</bcp14> be to launch a Donau validator (if
+ available). If no Donau validator is available, an application
+ <bcp14>SHOULD</bcp14> show a QR code with the content of the URI.
+ If multiple
+ Donau validators are registered, the user <bcp14>SHOULD</bcp14> be able to choose
+ which application to launch. This allows users with multiple
+ validators to choose which validator to perform the operation
+ with.
+ </t>
+ <!--<t>
+ An application <bcp14>SHOULD</bcp14> allow dereferencing a "donau://" URI even
+ if the action of that URI is not registered in the "Donau URI
+ Actions" sub-registry.
+ </t>-->
+ <t>
+ Validators <bcp14>MUST</bcp14> use HTTP over TLS when processing a "<tt>donau</tt>" URI.
+ The base origin <bcp14>SHOULD</bcp14> be shown to the
+ user to indicate which authority issued the proof of donation.
+ Alternatively, specific validation apps <bcp14>MAY</bcp14> only accept 'donau'
+ URLs from a specific set of hard-coded authorities and simply display
+ an error message when given 'donau' URLs from other authorities.
+ </t>
+</section>
+
+<section anchor="examples">
+ <name>Examples</name>
+ <figure>
+ <artwork><![CDATA[
+ ; Minimal example with a simple base and simple taxid
+ donau://example.com/
+ ?year=2025&id=7560001010000&
+ salt=1234&
+ total=EUR:15&
+ sig=ED25519:
+ H9PM3BW3P8MEKB34GZ0G1F7JSNVX7B8AHXRFFMS37QZM7TXZ5MWPXTEDZZGN1
+ QRB1AFPKNCFXJB39NJHP3BAFGCZSCXHEYPHA1YJY28
+
+ ; Example with percent-encoded taxid containing '/'
+ donau://donau.test.taler.net/
+ ?year=2025&id=123%2F456%2F789&
+ salt=1234&
+ total=TESTKUDOS:1&
+ sig=ED25519:
+ B14WGS43FFPEB8JMSR6W1H8M6KH9AV33JFH376R6PM2MNH4GR24FP1C93C4ZPDG2
+ 1W5WY4SASZQ4CRS427F4WJZJFZMQ5Y4HZNXGY30
+
+ ; Example with a base URL that includes path components
+ donau://admin.ch/taxes/donau/
+ ?year=2025&id=7560001010000&
+ salt=1234&
+ total=EUR:15&
+ sig=ED25519:
+ H9PM3BW3P8MEKB34GZ0G1F7JSNVX7B8AHXRFFMS37QZM7TXZ5MWPXTEDZZGN1
+ QRB1AFPKNCFXJB39NJHP3BAFGCZSCXHEYPHA1YJY28
+]]>
+ </artwork>
+ </figure>
+</section>
+
+<section anchor="verification">
+ <name>Verification of a Donau URI</name>
+ <t>
+ The verification requires the Donau verification application to test
+ if a given taxpayer is entitled to a tax reduction.
+ For doing this, the Donau verification application must
+ verify that the Donau URI corresponds to a valid Donau donation
+ statement. The Donau verification application <bcp14>MUST</bcp14> verify the
+ validity of the donation statement. There are two possibilities:
+ signature and total are available, or at least one is not available.
+ </t>
+ <t>
+ If signature and total are available, then the verification
+ application <bcp14>MUST</bcp14> verify
+ that the signature is valid for the server key (see <xref
+ target="get-server-keys"/> to get the key).
+ </t>
+ <t>
+ If either or both are missing, the application <bcp14>MUST</bcp14> download them from
+ the get donation statement endpoint <xref target="get-donation-statement"/>.
+ </t>
+
+</section>
+<section anchor="get-server-keys">
+ <name>Obtaining Donau Server Public Keys</name>
+ <t>
+ The verification app <bcp14>MUST</bcp14> obtain the signing public key
+ corresponding to the base for the given year.
+ The key <bcp14>MAY</bcp14> be retrieved from a
+ cache. If no key for this base and this year is available in the
+ cache, the verification app <bcp14>MUST</bcp14> download the key from the
+ base. The Donau server <bcp14>MUST</bcp14> provide the key at the /keys
+ endpoint. If the key is not available, no verification can take place
+ and the validator <bcp14>MUST</bcp14> return an appropriate error.
+
+ The verification app <bcp14>SHOULD</bcp14> cache downloaded signing
+ public keys for the current year.
+ </t>
+ <ul>
+ <li>Endpoint: /keys</li>
+ <li>Method: GET</li>
+ <li>Syntax: base/keys</li>
+ <li>Syntax response: defined hereunder</li>
+ <li>References: [this.I-D]</li>
+ </ul>
+
+ <t>
+ Each of the "<tt>signkeys</tt>" is valid between "<tt>stamp_start</tt>" and
+ "<tt>stamp_expire</tt>" and the public "<tt>key</tt>" returned is encoded using Base 32
+ U Crockford encoding <xref target="base32-U-crockford"/>.
+ </t>
+
+ <sourcecode>
+ <![CDATA[
+; Core JSON tokens (simplified; assumes standard JSON dialect)
+JSONString = DQUOTE *(%x20-21 / %x23-5B /
+ %x5D-10FFFF / "\" EscapedChar) DQUOTE
+UCrockford = *( ALPHA32 / "-" )
+ALPHA32 = DIGIT / LETTER
+DIGIT = %x30-39 ; 0-9
+LETTER = %x41-48 / %x4A-4E / %x50-5A / %x61-68 / %x6A-6E / %x70-7A
+JSONUCrockfordString = DQUOTE UCrockford DQUOTE
+EscapedChar = %x22 / %x5C / %x2F / %x62 / %x66 /
+ %x6E / %x72 / %x74 / "u" 4HEXDIG
+JSONNumber = [ "-" ] 1DIGIT *( DIGIT ) [ "." 1DIGIT *( DIGIT ) ]
+ [ ( "e" / "E" ) [ "+" / "-" ] 1DIGIT *( DIGIT ) ]
+JSONBool = "true" / "false"
+JSONNull = "null"
+JSONArray = "[" [ JSONException *( "," JSONException ) ] "]"
+JSONObject = "{" [ JSONMember *( "," JSONMember ) ] "}"
+JSONMember = JSONString ":" JSONException
+JSONException = JSONString / JSONNumber / JSONObject /
+ JSONArray / JSONBool / JSONNull
+
+; Specific DonauKeysResponse structure
+DonauKeysResponse = "{"
+ JSONMemberSep
+ "}"
+JSONMemberSep = version , domain , base_url , currency ,
+ currency_fraction_digits , donation_units , signkeys
+
+version = DQUOTE "version" DQUOTE ":" JSONString
+domain = DQUOTE "domain" DQUOTE ":" JSONString
+base_url = DQUOTE "base_url" DQUOTE ":" JSONString
+currency = DQUOTE "currency" DQUOTE ":" JSONString
+currency_fraction_digits = DQUOTE "currency_fraction_digits"
+ DQUOTE ":" JSONNumber
+EDDSAPubKey = JSONUCrockfordString
+SignKey = DQUOTE "key" DQUOTE ":" EDDSAPubKey
+donation_units = DQUOTE "donation_units" DQUOTE ":" "["
+ DonationUnitKeyGroup *(
+ "," DonationUnitKeyGroup ) "]"
+signkeys = DQUOTE "signkeys" DQUOTE ":" "[" SignKey
+ *( "," SignKey ) "]"
+
+DonationUnitKeyGroup = "{" cipher_field "," value_field ","
+ donation_units_array "}"
+cipher_field = DQUOTE "cipher" DQUOTE ":" (
+ DQUOTE "RSA" DQUOTE / DQUOTE "CS" DQUOTE )
+value_field = DQUOTE "value" DQUOTE ":" JSONNumber
+donation_units_array = DQUOTE "donation_units" DQUOTE ":" "["
+ DUNK_UNIT_KEY *(
+ "," DUNK_UNIT_KEY ) "]"
+
+; donation unit entries differ depending on cipher
+DUNK_UNIT_KEY = "{" base_fields "," key_specific "}"
+base_fields = DQUOTE "year" DQUOTE ":" JSONNumber
+ [ "," DQUOTE "lost" DQUOTE ":" JSONBool ]
+key_specific = ( DQUOTE "rsa_pub" DQUOTE ":" JSONObject ) /
+ ( DQUOTE "cs_pub" DQUOTE ":" JSONString )
+
+SignKey = "{" DQUOTE "key" DQUOTE ":" JSONObject ","
+ DQUOTE "year" DQUOTE ":" JSONNumber "}"
+ ]]>
+ </sourcecode>
+
+ <t>Example, a response to a GET request to the <tt>/keys</tt> endpoint.</t>
+ <sourcecode>
+ <![CDATA[
+ { "signkeys":
+ [
+ {
+ "stamp_start": {"ts_s": 42 },
+ "stamp_expire": {"ts_s": 43 },
+ "key": "XXXXXXXXXXXXXXXX"
+ }
+ ]
+ }
+ ]]>
+ </sourcecode>
+</section>
+
+
+<section anchor="get-donation-statement">
+ <name>Donation Statement Retrieval</name>
+ <t>
+ If the Donau URI does not contain the total or the signature, the
+ verification app <bcp14>MUST</bcp14> download them from the <tt>/donation-statement</tt>
+ endpoint of the base.<br/>
+
+ The verification app <bcp14>MUST</bcp14> compute the hash of the donor
+ taxpayer ID <tt>hash-donor-id</tt> using SHA-512 <xref target="RFC6234"/>
+ over the exact UTF-8 bytes of the taxpayer ID string, followed by a single
+ NUL byte (0x00), followed by the salt string, followed by a final NUL byte (0x00):
+ <tt>hash-donor-id = SHA-512(taxid || 0x00 || salt || 0x00)</tt>.
+ Here, <tt>taxid</tt> is the UTF-8 string obtained by percent-decoding the <tt>taxid-enc</tt> path segment.
+ The verification app <bcp14>MUST</bcp14> contact the
+ base at the endpoint <tt>/donation-statement</tt> with the year and <tt>hash-donor-id</tt>.
+
+ The hash of the donor taxpayer ID <tt>hash-donor-id</tt> <bcp14>MUST</bcp14> be encoded
+ using Base 32 U Crockford
+ encoding <xref target="base32-U-crockford"/>.
+ </t>
+
+ <ul>
+ <li>Endpoint: /donation-statement</li>
+ <li>Method: GET</li>
+ <li>Syntax: base/donation-statement/{year}/{hash-donor-id}</li>
+ <li>References: [this.I-D]</li>
+ </ul>
+
+ <t>
+ Servers implementing the donation-statement endpoint
+ <bcp14>MUST</bcp14> respect the
+ following syntax; all three fields (<tt>total-field</tt>, <tt>sig-field</tt>, <tt>pub-field</tt>) <bcp14>MUST</bcp14> be included.
+
+ The total amount is a string formed first of the currency (in capital
+ letters) then ":" and then the value (can be an integer or a decimal
+ number).
+ </t>
+
+ <sourcecode>
+ <![CDATA[
+json-object = "{" ws field-list ws "}"
+
+field-list = field *(ws "," ws field)
+field = total-field / sig-field / pub-field
+
+; Allow any order of the three fields
+total-field = DQUOTE "total" DQUOTE ws ":" ws
+ DQUOTE currency ":" value DQUOTE
+sig-field = DQUOTE "donation_statement_sig" DQUOTE ws ":"
+ ws DQUOTE signature DQUOTE
+pub-field = DQUOTE "donau_pub" DQUOTE ws ":" ws
+ DQUOTE signature DQUOTE ; same format as signature
+
+currency = 1*(%x41-5A) ; A-Z uppercase letters
+value = int / decimal
+int = ["-"] 1*DIGIT
+decimal = ["-"] 1*DIGIT "." 1*DIGIT
+
+signature = 1*(ALPHA / DIGIT / "=")
+
+; Common tokens
+ws = *WSP
+DQUOTE = %x22 ; "
+WSP = %x20 / %x09
+DIGIT = %x30-39
+ALPHA = %x41-5A / %x61-7A
+ ]]>
+ </sourcecode>
+
+ <t>Example of an element of USD 100.00 :</t>
+ <sourcecode>
+ <![CDATA[
+{
+ "total": "USD:100",
+ "donation_statement_sig": "SIGNATURE",
+ "donau_pub": "EDDSA_PUBLIC_KEY"
+}
+ ]]>
+ </sourcecode>
+</section>
+
+
+<section anchor="signature-total-available">
+ <name>Verification if Signature and Total are Available</name>
+ <t>
+ The verification app <bcp14>MUST</bcp14> verify that the signature corresponds to
+ the claimed values.
+
+ If the information is not in the URI, the verification app <bcp14>MUST</bcp14>
+ download the total and the signature from the
+ base using the GET <tt>/donation-statement</tt> endpoint <xref
+ target="get-donation-statement"/>. Otherwise, it <bcp14>SHOULD</bcp14> use the
+ value given in the URI.
+
+ The verification of the signature is done using EdDSA as
+ specified in <xref target="RFC8032" />.
+
+ The verification <bcp14>MAY</bcp14> be done with the following instructions.
+ The signed data is the concatenation of the following fields
+ in network byte order (big-endian):
+ </t>
+
+ <ul>
+ <li>size (4 bytes): 32-bit unsigned integer with the total length of the signed data in bytes.</li>
+ <li>purpose (4 bytes): 32-bit unsigned integer with the constant value <tt>1500</tt>.</li>
+ <li>total value (8 bytes): integer part as an unsigned 64-bit integer.</li>
+ <li>total fraction (4 bytes): fractional part as an unsigned 32-bit integer in units of 1/100000000.</li>
+ <li>currency (12 bytes): ASCII string, left-aligned with zero-padding on the right to 12 bytes.</li>
+ <li>hash of donor taxpayer ID (64 bytes): <tt>hash-donor-id = SHA-512( UTF-8(taxid) || 0x00 || UTF-8(salt) || 0x00 )</tt>.</li>
+ <li>year (4 bytes): 32-bit unsigned integer (the donation year).</li>
+ </ul>
+</section>
+
+
+<section anchor="signature">
+ <name>Creating Donation Statement Signatures</name>
+ <t>
+ The server signing the donation statement <bcp14>MUST</bcp14> use the Sign(d,message) procedure implemented as defined in <xref target="RFC8032" />.
+ </t>
+ <t>
+ The signature over the public key covers a 32-bit pseudo header
+ conceptually prefixed to the donation data fields.
+ The wire format is illustrated
+ in <xref target="figure_donausigwithpseudo"/>.
+ </t>
+ <figure anchor="figure_donausigwithpseudo">
+ <name>The Format for Creating Donation Statement Signatures</name>
+ <artwork name="" type="" alt="">
+0 8 16 24 32 40 48 56
++-----+-----+-----+-----+-----+-----+-----+-----+
+| SIZE | PURPOSE (1500) |
++-----+-----+-----+-----+-----+-----+-----+-----+
+| TOTAL value |
++-----+-----+-----+-----+-----+-----+-----+-----+
+| TOTAL fraction | CURRENCY |
++-----+-----+-----+-----+ +
+| |
++-----+-----+-----+-----+-----+-----+-----+-----+
+| SHA512 of the donor ID |
+/ /
+/ /
++-----+-----+-----+-----+-----+-----+-----+-----+
+| YEAR |
++-----+-----+-----+-----+
+ </artwork>
+ </figure>
+ <dl newline="false">
+ <dt>SIZE:</dt>
+ <dd>
+ A 32-bit value containing the length of the signed data in bytes
+ in network byte order.
+ </dd>
+ <dt>PURPOSE:</dt>
+ <dd>
+ A 32-bit signature purpose flag in network byte order. The value of this
+ field <bcp14>MUST</bcp14> be 1500. It defines the context in which
+ the signature is created so that it cannot be reused in other parts
+ of the protocol that might include possible future extensions.
+ The value of this field corresponds to an entry in the
+ GANA "GNUnet Signature Purposes" registry <xref target="GANA"/>.
+ </dd>
+ <dt>TOTAL value:</dt>
+ <dd>
+ The integer part of the total value.
+ Unsigned integer containing the integer part of the value for the total.
+ It is represented using a 64 bit value (in big endian).
+ </dd>
+ <dt>TOTAL fraction:</dt>
+ <dd>
+ 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.
+ </dd>
+ <dt>TOTAL currency</dt>
+ <dd>
+ A string representing the currency. ASCII, left-aligned and zero-padded to exactly 12 bytes.
+ </dd>
+ <dt>HASH:</dt>
+ <dd>The SHA512 hash code for the donor ID.</dd>
+ <dt>YEAR:</dt>
+ <dd>The year on a 32 bit unsigned integer in big endian.</dd>
+ </dl>
+</section>
+
+<section anchor="signature-verification">
+ <name>Validating Donation Statement Signatures</name>
+ <t>
+ The signature verification step is taking the data presented in the
+ figure <xref target="figure_donausigwithpseudo" /> as input.
+ The signature <bcp14>MUST</bcp14> be verified using the EdDSA scheme described in
+ <xref target="RFC8032" /> the procedure is
+ <tt>Verify(zk,message,signature)</tt>.
+ Public key and signature, which are
+ encoded in Base 32 U Crockford in the URL,
+ <bcp14>MUST</bcp14> first be decoded to obtain the
+ respective binary value.
+ </t>
+ <t>
+ The Sign(d,message) and Verify(zk,message,signature) procedures <bcp14>MUST</bcp14>
+ be implemented as defined in <xref target="RFC8032" />.
+ </t>
+</section>
+
+
+<section anchor="base32-U-crockford">
+ <name>Base 32 Representation of Binary Data</name>
+ <t>
+ All binary data <bcp14>MUST</bcp14> be encoded to be transmitted. For encoding, one
+ <bcp14>MUST</bcp14> use the Base32 U Crockford encoding. This is a variation of the
+ base32 encoding <xref target ="RFC4648" />. This encoding is presented
+ in detail in the appendix of the RFC for GNU Name System <xref target="RFC9498" />
+ </t>
+ <t>
+ The encoding works similarly to the standard, but uses another Base 32
+ Alphabet. The new alphabet is given in the Table <xref target="figure_base32_encoding" />, below.
+ </t>
+
+ <figure anchor="figure_base32_encoding">
+ <name>The Base 32 Encoding Alphabet.</name>
+ <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[
+Value Encoding Value Encoding Value Encoding Value Encoding
+ 0 0 9 9 18 J 27 V
+ 1 1 10 A 19 K 28 W
+ 2 2 11 B 20 M 29 X
+ 3 3 12 C 21 N 30 Y
+ 4 4 13 D 22 P 31 Z
+ 5 5 14 E 23 Q
+ 6 6 15 F 24 R (pad) =
+ 7 7 16 G 25 S
+ 8 8 17 H 26 T
+
+ ]]>
+ </artwork>
+ </figure>
+
+ <t>
+ To prevent optical character reading (OCR) problems, a system decoding
+ binary data encoded with base 32 U Crockford <bcp14>MUST</bcp14>
+ accept the codes presented in the Table <xref target="figure_base32_decoding"/>, below.
+ System reading a <tt>U</tt> <bcp14>MUST</bcp14> evaluate it as a <tt>V</tt>.
+ </t>
+
+ <figure anchor="figure_base32_decoding">
+ <name>The Base 32 Decoding Alphabet.</name>
+ <artwork name="" type="" align="left" alt=""><![CDATA[
+Value Encoding Value Encoding Value Encoding Value Encoding
+ 0 0 9 9 18 J|j 27 V|v|u|U
+ 1 1|i|I|l|L 10 A|a 19 K|k 28 W|w
+ 2 2 11 B|b 20 M|m 29 X|x
+ 3 3 12 C|c 21 N|n 30 Y|y
+ 4 4 13 D|d 22 P|p 31 Z|z
+ 5 5 14 E|e 23 Q|q
+ 6 6 15 F|f 24 R|r (pad) =
+ 7 7 16 G|g 25 S|s
+ 8 8 17 H|h 26 T|t
+ ]]></artwork>
+ </figure>
+
+
+</section>
+
+<section anchor="security">
+ <name>Security Considerations</name>
+ <t>
+ Validator applications <bcp14>MUST</bcp14> include protections
+ against repeated validations of the same donation statement
+ with the same salt and year. Specifically, when summing up
+ multiple donation statements for the same taxpayer and
+ tax year, the <bcp14>MUST</bcp14> keep enough state to add
+ up the maximum total amounts per salt if multiple donation
+ statements are submitted with the same salt.
+ </t>
+</section>
+
+
+<section anchor="iana">
+ <name slugifiedName="name-iana-considerations">IANA Considerations</name>
+ <t>
+ IANA maintains the "Uniform Resource Identifier (URI) Schemes"
+ registry that contains an entry for the 'donau' URI scheme. IANA is
+ requested to update that entry to reference this document when
+ published as an RFC.
+ </t>
+ <dl indent="3" newline="false" spacing="normal">
+ <dt>Scheme name:</dt>
+ <dd> donau</dd>
+ <dt>Status:</dt>
+ <dd> provisional</dd>
+ <dt>URI scheme syntax:</dt>
+ <dd>See <xref target="syntax" format="default" sectionFormat="of" derivedContent="Section 3"/> of [This.I-D].</dd>
+ <dt>URI scheme semantics:</dt>
+ <dd>See <xref target="semantics" format="default" sectionFormat="of" derivedContent="Section 4"/> of [This.I-D].</dd>
+ <dt>Applications/protocols that use this scheme name:</dt>
+ <dd> GNU Taler</dd>
+ <dt>Contact:</dt>
+ <dd>
+ <t><contact fullname="Christian Grothoff"/> <grothoff@gnu.org></t>
+ </dd>
+ <dt>Change controller:</dt>
+ <dd>
+ <t><contact fullname="Christian Grothoff"/> <grothoff@gnu.org></t>
+ </dd>
+ <dt>References:</dt>
+ <dd> See <xref target="refs" format="default" sectionFormat="of" derivedContent="Section 13"/> of [This.I-D].</dd>
+ </dl>
+</section>
+
+
+</middle>
+
+<back xmlns="">
+
+
+
+
+ <references anchor="refs">
+ <name>Normative References</name>
+
+ <xi:include href="https://bib.ietf.org/public/rfc/bibxml/reference.RFC.2119.xml"/>
+
+ <xi:include href="https://bib.ietf.org/public/rfc/bibxml/reference.RFC.3986.xml"/>
+
+ <xi:include href="https://bib.ietf.org/public/rfc/bibxml/reference.RFC.4343.xml"/>
+
+ <xi:include href="https://bib.ietf.org/public/rfc/bibxml/reference.RFC.8174.xml"/>
+
+ <xi:include href="https://bib.ietf.org/public/rfc/bibxml/reference.RFC.5234.xml"/>
+
+ <xi:include href="https://bib.ietf.org/public/rfc/bibxml/reference.RFC.6234.xml"/>
+
+ <xi:include href="https://bib.ietf.org/public/rfc/bibxml/reference.RFC.8032.xml"/>
+
+ <xi:include href="https://bib.ietf.org/public/rfc/bibxml/reference.RFC.9498.xml"/>
+
+ <xi:include href="https://bib.ietf.org/public/rfc/bibxml/reference.RFC.8905.xml"/>
+
+ <reference anchor="ISO18004" target="https://www.iso.org/standard/83389.html" quoteTitle="true" derivedAnchor="ISO18004">
+ <front>
+ <title>Information technology - Automatic identification and data capture techniques - QR Code bar code symbology specification</title>
+ <author>
+ <organization showOnFrontPage="true">ISO/IEC</organization>
+ </author>
+ <date month="August" year="2024"/>
+ </front>
+ <seriesInfo name="ISO/IEC" value="18004:2024"/>
+ </reference>
+ </references>
+
+ <references>
+ <name>Informational References</name>
+
+ <xi:include href="https://bib.ietf.org/public/rfc/bibxml/reference.RFC.4648.xml"/>
+
+
+ <reference anchor="GANA" target="https://gana.gnunet.org/">
+ <front>
+ <title>GNUnet Assigned Numbers Authority (GANA)</title>
+ <author><organization>GNUnet e.V.</organization>
+ </author>
+ <date month="April" year="2020" />
+ </front>
+ </reference>
+
+ <reference anchor="BaThesis" target="https://www.taler.net/papers/donau-thesis.pdf">
+ <front>
+ <title>Tax-deductable Privacy-Preserving Donations</title>
+ <author initials="J.C." surname="Casaburi" fullname="Johannes Casaburi">
+ <organization>Bern University of Applied Science, Bachelor Thesis</organization>
+ </author>
+ <author initials="L.M." surname="Matya" fullname="Lukas Matya">
+ <organization>Bern University of Applied Science, Bachelor Thesis</organization>
+ </author>
+ </front>
+ </reference>
+ </references>
+
+<section anchor="appendix-test-vectors">
+ <name>Appendix. Test Vector: Verify from URI</name>
+ <t>
+ This appendix shows how to verify a donation statement starting from a
+ received URI. Public key is fetched from the Donau base.
+ </t>
+
+ <figure>
+ <artwork><![CDATA[
+Example URI:
+donau://donau.test.taler.net/?year=2025&id=123%2F456%2F789&
+ salt=AWNFDRFT0WX45W4Y32A9DJA03S1EF66GFQZ9EV5EF9JTHWZ37WR0&
+ total=TESTKUDOS:1&
+ sig=ED25519:
+ B14WGS43FFPEB8JMSR6W1H8M6KH9AV33JFH376R6PM2MNH4GR24FP1C93C4ZPDG21
+ W5WY4SASZQ4CRS427F4WJZJFZMQ5Y4HZNXGY30
+
+Extracted fields:
+- base: donau.test.taler.net
+- year: 2025
+- taxid: 123%2F456%2F789
+- taxid (decoded): 123/456/789
+- salt: AWNFDRFT0WX45W4Y32A9DJA03S1EF66GFQZ9EV5EF9JTHWZ37WR0
+- total: TESTKUDOS:1
+- signature: ED25519:B14WGS43FFPEB8JMSR6W1H8M6KH9AV33JFH376R6PM2MNH4
+ GR24FP1C93C4ZPDG21W5WY4SASZQ4CRS427F4WJZJFZMQ5Y4HZNXGY30
+
+Fetched public key for year 2025 from https://donau.test.taler.net/keys:
+- pub: 2FRN2CAK9DMDWE157W6HY97RAVSP0ZCCC08X9N6JD2MK7413XXZG
+]]></artwork>
+ </figure>
+
+ <t>Verification steps:</t>
+ <ol>
+ <li>Input (URI):<br/>
+<tt>donau://donau.test.taler.net/?year=2025&id=123%2F456%2F789&
+salt=AWNFDRFT0WX45W4Y32A9DJA03S1EF66GFQZ9EV5EF9JTHWZ37WR0&
+total=TESTKUDOS:1&
+sig=ED25519:B14WGS43FFPEB8JMSR6W1H8M6KH9AV33JFH376R6PM2MNH4GR24FP1C93C4ZPDG21
+W5WY4SASZQ4CRS427F4WJZJFZMQ5Y4HZNXGY30</tt></li>
+ <li>Parse fields:<br/>
+ - base: <tt>donau.test.taler.net</tt><br/>
+ - year: <tt>2025</tt> (4 digits)<br/>
+ - taxid-enc: <tt>123%2F456%2F789</tt><br/>
+ - taxid (UTF-8, percent-decoded, no trimming): <tt>123/456/789</tt><br/>
+ - salt (ASCII): <tt>AWNFDRFT0WX45W4Y32A9DJA03S1EF66GFQZ9EV5EF9JTHWZ37WR0</tt><br/>
+ - total (amount string): <tt>TESTKUDOS:1</tt><br/>
+ - sig (Crockford Base32, algorithm ED25519): <tt>B14WGS...XGY30</tt></li>
+ <li>Public signing key (Crockford Base32) (from <tt>/keys</tt>):<br/>
+<tt>2FRN2CAK9DMDWE157W6HY97RAVSP0ZCCC08X9N6JD2MK7413XXZG</tt></li>
+ <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/>
+ - length: 64 bytes<br/>
+ - hex:<br/>
+<tt>4aaa1e16fc5be44842b863b1f17da39296ca7b3529a720e11aba9c8bd729f7a 1e2bb0b9a39c02d271da5dd15aea66ce95be78bcaf380de19a0bdbcd8a7938f1b</tt><br/>
+ - Crockford Base32 (for HTTP endpoints):<br/>
+<tt>9AN1W5QWBFJ4GGNRCERZ2ZD3JABCMYSN56KJ1R8TQAE8QNS9YYGY5ERBK 8WW0B973PJXT5DEMSPEJPZ7HF5F706Y36GBVF6RMY9RY6R</tt></li>
+ <li>Total amount encoding (<tt>TALER_AmountNBO</tt>):<br/>
+ - currency (12 bytes): <tt>"TESTKUDOS"</tt> then <tt>0x00</tt> x 3<br/>
+ - value (uint64 BE): <tt>1</tt> -> <tt>0x0000000000000001</tt><br/>
+ - fraction (uint32 BE): <tt>0</tt> -> <tt>0x00000000</tt></li>
+ <li>Signed message <tt>M</tt> layout (network byte order, total 100 bytes):<br/>
+ - [0000..0003] 4 bytes <tt>size</tt>: <tt>0x00000064</tt><br/>
+ - [0004..0007] 4 bytes <tt>purpose</tt>: <tt>0x000005DC</tt> (1500)<br/>
+ - [0008..0015] 8 bytes <tt>amount.value</tt>: <tt>0x0000000000000001</tt><br/>
+ - [0016..0019] 4 bytes <tt>amount.fraction</tt>: <tt>0x00000000</tt><br/>
+ - [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/>
+ - [0032..0095] 64 bytes <tt>i.hash</tt>: hash of donor taxpayer ID <tt>hash-donor-id</tt><br/>
+ - [0096..0099] 4 bytes <tt>year</tt>: <tt>0x000007E9</tt> (2025)</li>
+ <li>Message <tt>M</tt> (hex, 100 bytes):<br/>
+<tt>00000064 000005dc 0000000000000001 00000000 544553544b55444f53000000 4aaa1e16fc5be44842b863b1f17da39296ca7b3529a720e11aba9c8bd729f7a1e2bb0b 9a39c02d271da5dd15aea66ce95be78bcaf380de19a0bdbcd8a7938f1b 000007e9</tt></li>
+ <li>Signature (ED25519, Crockford Base32 -> bytes):<br/>
+ - length: 64 bytes<br/>
+ - R (first 32 bytes, hex):<br/>
+<tt>5849c864837bece5a254ce0dc0c51434e2956c6393e2339b06b5054ac490c088</tt><br/>
+ - S (last 32 bytes, hex):<br/>
+<tt>fb05891b09fb36020f0bcf132acfee46632411de4e4bf27fe972f891fd7b0f0c</tt></li>
+ <li>Public key (Ed25519, Crockford Base32 -> bytes):<br/>
+ - length: 32 bytes<br/>
+ - hex:<br/>
+<tt>13f15131534b68de38253f0d1f24f856f3607d8c6011d4d4d268a9339023ef7f</tt></li>
+ <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>
+ <li>Negative check (optional): flip one bit of <tt>M</tt> or <tt>sig</tt> and repeat; verification <bcp14>MUST</bcp14> fail.</li>
+ </ol>
+</section>
+
+<section numbered="false">
+ <name>Acknowledgements</name>
+ <t>
+ The authors thank Ted Hardie for his comments on an earlier version of the draft.
+ This work was funded in part by the European Commission through the
+ Horizon Europe program under project number 101135475 (TALER). It also
+ has received funding from the Swiss State Secretariat for Education,
+ Research and Innovation (SERI).
+ </t>
+</section>
+
+<!-- Change Log
+v00 2025-10-17 CG Initial version
+v01 2025-10-21 EB Including first reviews (motivations + change in URI structure)
+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
+ -->
+</back>
+</rfc>