commit ae7366d9645d8a0dae30202728ee9ce117ea6e30
parent a1f9f58d15ac6e740f936298decea0b75a3e9413
Author: Emmanuel Benoist <emmanuel.benoist@bfh.ch>
Date: Tue, 21 Oct 2025 18:37:26 +0200
Including the comments of our first reviewer
Diffstat:
1 file changed, 835 insertions(+), 0 deletions(-)
diff --git a/draft-grothoff-donau-01.xml b/draft-grothoff-donau-01.xml
@@ -0,0 +1,835 @@
+<?xml version="1.0" encoding="US-ASCII"?>
+<!DOCTYPE rfc SYSTEM "rfc2629.dtd" [
+<!ENTITY RFC2119 SYSTEM "http://xml.resource.org/public/rfc/bibxml/reference.RFC.2119.xml">
+<!ENTITY RFC3986 SYSTEM "http://xml.resource.org/public/rfc/bibxml/reference.RFC.3986.xml">
+<!ENTITY RFC8174 SYSTEM "http://xml.resource.org/public/rfc/bibxml/reference.RFC.8174.xml">
+<!ENTITY RFC5234 SYSTEM "http://xml.resource.org/public/rfc/bibxml/reference.RFC.5234.xml">
+<!ENTITY RFC6234 SYSTEM "http://xml.resource.org/public/rfc/bibxml/reference.RFC.6234.xml">
+<!ENTITY RFC8032 SYSTEM "http://xml.resource.org/public/rfc/bibxml/reference.RFC.8032.xml">
+<!ENTITY RFC4648 SYSTEM "http://xml.resource.org/public/rfc/bibxml/reference.RFC.4648.xml">
+<!ENTITY RFC9498 SYSTEM "http://xml.resource.org/public/rfc/bibxml/reference.RFC.9498.xml">
+<!ENTITY RFC8905 SYSTEM "http://xml.resource.org/public/rfc/bibxml/reference.RFC.8905.xml">
+]>
+<?xml-stylesheet type='text/xsl' href='rfc2629.xslt' ?>
+<!-- SEE ALSO: https://docs.taler.net/core/taler-uri.html -->
+<?rfc strict="yes" ?>
+<?rfc toc="yes" ?>
+<?rfc symrefs="yes"?>
+<?rfc sortrefs="yes" ?>
+<?rfc compact="yes" ?>
+<?rfc subcompact="no" ?>
+
+<rfc category="info"
+ docName="draft-grothoff-donau-01"
+ ipr="trust200902">
+<!-- FIXME ipr is copied from lsd0001, need to be updated -->
+ <front>
+ <title abbrev="The 'donau' URI scheme">
+ The 'donau' URI scheme for validation of Donau donation statements.
+ </title>
+
+ <author fullname="Christian Grothoff" initials="C.G." surname="Grothoff">
+ <organization>Bern University of Applied Sciences</organization>
+ <address>
+ <postal>
+ <street>Höheweg 80</street>
+ <street></street>
+ <city>Biel/Bienne</city>
+ <code>CH-2501</code>
+ <country>CH</country>
+ </postal>
+ <email>christian.grothoff@bfh.ch</email>
+ </address>
+ </author>
+
+ <author fullname="Emmanuel Benoist" initials="E.B." surname="Benoist">
+ <organization>Bern University of Applied Sciences</organization>
+ <address>
+ <postal>
+ <street>Höheweg 80</street>
+ <street></street>
+ <city>Biel/Bienne</city>
+ <code>CH-2501</code>
+ <country>CH</country>
+ </postal>
+ <email>emmanuel.benoist@bfh.ch</email>
+ </address>
+ </author>
+
+
+ <author fullname="Bohdan Potuzhnyi" initials="B.P." surname="Potuzhnyi">
+ <organization>Bern University of Applied Sciences</organization>
+ <address>
+ <postal>
+ <street>Höheweg 80</street>
+ <street></street>
+ <city>Biel/Bienne</city>
+ <code>CH-2501</code>
+ <country>CH</country>
+ </postal>
+ <email>bohdan.potuzhnyi@bfh.ch</email>
+ </address>
+ </author>
+
+
+ <author fullname="Florian Dold" initials="F.D." surname="Dold">
+ <organization>Taler Systems AG</organization>
+ <address>
+ <postal>
+ <street>7, rue de Mondorf</street>
+ <street></street>
+ <city>Erpeldange</city>
+ <code>L-5421</code>
+ <country>Luxembourg</country>
+ </postal>
+ <email>dold@taler.net</email>
+ </address>
+ </author>
+
+
+ <date day="21" month="October" 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-deductable
+ 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 cummulative 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 run its own server, it will not be possible to write inside the validation tool all the possible (changing) list of tax authorities servers. Hence a new URI scheme is needed that will triger the validation tool for any host, regardless of the name of the host.
+ </t>
+ </abstract>
+
+ </front>
+
+ <middle>
+
+<section anchor="introduction" title="Introduction">
+<t>
+ This document defines the 'donau' Uniform Resource Identifier (URI) <xref target="RFC3986" /> scheme
+ for triggering interactions with Donau validators.
+</t>
+
+<section title="Objective">
+<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 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 title="Requirements Language">
+<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"
+ title="Syntax of a 'donau' URI">
+ <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://" / "donau+http://" / "DONAU+HTTP://"
+ donau-URI = scheme base "?" year-param "&" taxid-param "&" salt-param
+ "&" amount-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" ] "=" year
+
+ tax-id-param = [ "id" / "ID" ] "=" tax-id-enc
+
+ salt-param = [ "salt" / "SALT" ] "=" alt
+
+ amount-param = [ "total" / "TOTAL" ] "=" amount
+
+ signature-param = [ "sig" / "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*( DIGIT )
+
+ ; Query parameters and signature encoding
+ amount = currency ":" unit [ "." fraction ]
+ currency = 1*ALPHA
+ unit = 1*( DIGIT )
+ fraction = 1*( DIGIT )
+ algo = "ED25519"
+ signature = *( ALPHA / DIGIT )
+]]>
+ </artwork>
+ </figure>
+</section>
+
+<section anchor="semantics" title="Semantics">
+ <t> Even if RFC3986 <xref target="RFC3986"/> explicitely writes that scheme names are case insensitive, lower and uper case variations are presented here to emphase this possibility. The applications encoding URI in a QR-code can profite from the possibility to encode the URI in upercase only which may be more efficient.
+ </t>
+ <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 MAY include
+ additional path segments (for example, <tt>https://admin.ch/taxes/donau/</tt>)
+ mapping to the Donau deployment behind reverse proxies. Validators MUST NOT
+ assume a specific domain naming scheme (such as <tt>donau.example</tt>) and
+ MUST accept bases with or without additional path components.
+ </t>
+ <t>
+ The year of a Donau URI referes to the year when the donations
+ have been done.
+ </t>
+ <t>
+ The taxid of a Donau URI referes 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 single path segment using percent-encoding
+ per <xref target="RFC3986"/>. Implementations MUST 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 '/' MUST be percent-encoded
+ as <tt>%2F</tt> if present in a tax identifier.
+ </t>
+ <t>
+ The salt of a Donau URI referes to the information used by the
+ Donau-wallet application to generate the Donau donation statement. This salt is
+ specific for each wallet, allowing a taxpayer to have many Donau
+ donation statements for the same year that should be treated as
+ cummulative by the validator application. The salt can also be
+ 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 amount should be used, while
+ the 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 must be
+ made over the information above (see <xref target="signature"/>)
+ and MUST 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 MUST be to launch a Donau validator (if
+ available). If no Donau validator is available, an application
+ SHOULD show a QR code with the content of the URI. If multiple
+ Donau validators are registered, the user SHOULD 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 SHOULD allow dereferencing a "donau://" URI even
+ if the action of that URI is not registered in the "Donau URI
+ Actions" sub-registry.
+ </t>-->
+ <t>
+ Donau-validators seeing a "<tt>donau://</tt>" URI MUST use HTTP over TLS when talking
+ to the respective network service.
+ Donau-validators seeing a "<tt>donau+http://</tt>" URI MUST use HTTP without TLS when talking
+ to the respective network service. Donau-validators SHOULD support
+ "<tt>donau+http://</tt>"-URIs only when run in developer or debug mode.
+ Validators would contact the base to obtain the public key
+ used for the signature. The base origin SHOULD also be shown to the
+ user to indicate which authority issued the proof of donation.
+ Alternatively, specific validation apps MAY 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>
+ <t>
+ Running "<tt>donau+http://</tt>"-URIs on a productive server MUST NOT be permitted, since it would be a huge security issue. These scheme is only used for testing purposes, for instance on <tt>localhost</tt>.
+ </t>
+
+</section>
+
+ <section anchor="examples" title="Examples">
+ <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:H9PM3BW3P8MEKB34GZ0G1F7JSNVX7B8AHXRFFMS37QZM7TXZ5MWPXTEDZZGN1QRB1AFPKNCFXJB39NJHP3BAFGCZSCXHEYPHA1YJY28
+
+ ; Example with percent-encoded taxid containing '/'
+ donau://donau.test.taler.net/?year=2025&id=123%2F456%2F789&salt=1234&total=TESTKUDOS:1&sig=ED25519:B14WGS43FFPEB8JMSR6W1H8M6KH9AV33JFH376R6PM2MNH4GR24FP1C93C4ZPDG21W5WY4SASZQ4CRS427F4WJZJFZMQ5Y4HZNXGY30
+
+ ; 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:H9PM3BW3P8MEKB34GZ0G1F7JSNVX7B8AHXRFFMS37QZM7TXZ5MWPXTEDZZGN1QRB1AFPKNCFXJB39NJHP3BAFGCZSCXHEYPHA1YJY28
+]]>
+ </artwork>
+</figure>
+
+</section>
+
+<section anchor="verification" title="Verification of a Donau URI">
+ <t>
+ The verification requires the Donau verification application to test
+ if a given taxpayer has got the right to be granted 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 MUST 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 will verify
+ that the signature is valid for the server key (see <xref
+ target="get-server-keys"/> to get the key).
+ </t>
+ <t>
+ If both are missing, the application MUST download them from
+ the get donation statement endpoint <xref target="get-donation-statement"/>.
+ </t>
+
+</section>
+<section anchor="get-server-keys" title="Access the Donau server public
+ keys">
+ <t>
+ The verification app MUST have a signing public key
+ corresponding to the base for the given year. The key MAY be retrieved from a
+ cache. If no key for this base and this year is available in the
+ cache, the verification app MUST download the key from the
+ base. The Donau server MUST provide the key at the /keys
+ entrypoint. If the key is not available, no verification can take place.
+
+ The verification app SHOULD cache downloaded signing
+ public keys for the current year.
+ </t>
+ <t>
+
+ <list style="symbols">
+ <t>Endpoint: /keys</t>
+ <t>Method: GET</t>
+ <t>Syntax: base/keys</t>
+ <t>Syntax response: defined hereunder</t>
+ <t>Contact: N/A</t>
+ <t>References: [this.I-D]</t>
+ </list>
+
+
+
+
+
+ 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"/>.
+
+ <sourcecode>
+ <![CDATA[
+; Core JSON tokens (simplified; assumes standard JSON for strings, numbers, booleans, null, arrays, objects)
+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>
+
+Example, a response to a GET request to the <tt>/key/</tt> endpoint.
+ <sourcecode>
+ <![CDATA[
+ {"signkeys":
+ [ "stamp_start":{"ts_s":42},
+ "stamp_expire":{"ts_s":43},
+ "key":"XXXXXXXXXXXXXXXX"
+ ]
+ }
+ ]]>
+ </sourcecode>
+
+
+ </t>
+</section>
+
+<section anchor="get-donation-statement" title="Get donation statement
+ and signature">
+ <t>
+ If the Donau-URI does not contain the total or the signature, the
+ verification app MUST download them from the <tt>/donation-statement/</tt>
+ endpoint of the base.<br/>
+
+ The verification app will compute the donor hash H 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>H = 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.
+ This produces the <tt>hash-donor-id</tt>. The verification app will contact the
+ base in the endpoint <tt>/donation-statement</tt> with the year and the hash-donor-id.
+
+ The <tt>hash-donor-id</tt> must be encoded using Base 32 U Crockford
+ encoding <xref target="base32-U-crockford"/>.
+
+
+ <list style="symbols">
+ <t>Endpoint: /donation-statement</t>
+ <t>Method: GET</t>
+<t>Syntax: base/donation-statement/{year}/{hash-donor-id}</t>
+<t>Contact: N/A</t>
+<t>References: [this.I-D]</t>
+</list>
+
+
+Servers implementing the donation-statement endpoint MUST respect the
+following syntax; all three fields (<tt>total-field</tt>, <tt>sig-field</tt>, <tt>pub-field</tt>) MUST be included.
+
+The 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).
+
+ <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>
+
+
+
+Example of an element of USD 100.00 :
+ <sourcecode>
+ <![CDATA[
+{
+ total: "USD:100",
+ donation_statement_sig: "SIGNATURE",
+ donau_pub: "EDDSA_PUBLIC_KEY"
+}
+ ]]>
+ </sourcecode>
+
+
+ </t>
+</section>
+<section anchor="signature-total-available" title="Signature and
+ total are available">
+ <t>
+ The verification app MUST verify that the signature corresponds to
+ the claimed values.
+
+ If the information is not in the URI, the verification app MUST download the total and the signature from the
+ base using the GET /donation-statement/ endpoint <xref
+ target="get-donation-statement"/>. Otherwise, it SHOULD use the
+ value given in the URI.
+
+ The verification of the signature is done using EdDSA as
+ specified in <xref target="RFC8032" />.
+
+ 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):
+
+ <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, left-aligned and zero-padded to 12 bytes.</li>
+ <li>donor hash H (64 bytes): <tt>H = 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>
+
+</t>
+</section>
+
+<section anchor="signature" title="Signature of the donation statement ">
+ <t>
+ The server signing the donation statement <bcp14>MUST</bcp14> use the Sign(d,message) procedure implemented as defined in <xref target="RFC8032" />.
+ </t>
+ <figure anchor="figure_signature_data" title="The binary representation of the data to sign">
+ <artwork name="" type="" align="left" alt=""><![CDATA[
+0
+]]></artwork>
+ </figure>
+
+
+
+ <t>
+ The signature over the public key covers a 32-bit pseudo header
+ conceptually prefixed to the EXPIRATION and BDATA fields.
+ The wire format is illustrated
+ in <xref target="figure_rrsigwithpseudo"/>.
+ </t>
+ <figure anchor="figure_rrsigwithpseudo">
+ <name>The Wire Format Used for Creating the Signature of the RRBLOCK</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 on 64 bits 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" title="Signature verification for a donation statement">
+ <t>
+The signature verification step is taking the data presented in the figure <xref target="figure_signature_data" /> as
+input. Signature MUST be verified using the EdDSA scheme described in
+<xref target="RFC8032" /> the procedure is Verify(zk,message,signature). Public key and signature are given
+encoded in Base 32 U Crockford MUST first be decoded to get a binary
+out of it.
+ </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" title="Base 32 representation of
+ binary data">
+<t>All binary data MUST be encoded to be transmitted. For encoding, one
+MUST use the Base32 U Crockford encoding. This is a variation of the
+base32 encoding <xref target ="RFC4648" />. This encoding is presented
+in details 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" title="The Base 32 Encoding Alphabet.">
+ <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[
+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 MUST
+accept the codes presented in the Table <xref target="figure_base32_decoding"/>, below. System reading a U
+MUST evaluate it as a V.
+</t>
+
+ <figure anchor="figure_base32_decoding" title="The Base 32 Decoding Alphabet.">
+ <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="appendix-test-vectors" title="Appendix. Test Vector: Verify from URI">
+ <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:B14WGS43FFPEB8JMSR6W1H8M6KH9AV33JFH376R6PM2MNH4GR24FP1C93C4ZPDG21W5WY4SASZQ4CRS427F4WJZJFZMQ5Y4HZNXGY30
+
+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:B14WGS43FFPEB8JMSR6W1H8M6KH9AV33JFH376R6PM2MNH4GR24FP1C93C4ZPDG21W5WY4SASZQ4CRS427F4WJZJFZMQ5Y4HZNXGY30
+
+Fetched public key for year 2025 from https://donau.test.taler.net/keys:
+- pub: 2FRN2CAK9DMDWE157W6HY97RAVSP0ZCCC08X9N6JD2MK7413XXZG
+ ]]></artwork>
+ </figure>
+
+ <t>Verification steps:</t>
+ <list style="numbers">
+ <t>Input (URI):<br/>
+<tt>donau://donau.test.taler.net/?year=2025&id=123%2F456%2F789&salt=AWNFDRFT0WX45W4Y32A9DJA03S1EF66GFQZ9EV5EF9JTHWZ37WR0&total=TESTKUDOS:1&sig=ED25519:B14WGS43FFPEB8JMSR6W1H8M6KH9AV33JFH376R6PM2MNH4GR24FP1C93C4ZPDG21W5WY4SASZQ4CRS427F4WJZJFZMQ5Y4HZNXGY30</tt></t>
+ <t>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></t>
+ <t>Public signing key (Crockford Base32) (from <tt>/keys</tt>):<br/>
+<tt>2FRN2CAK9DMDWE157W6HY97RAVSP0ZCCC08X9N6JD2MK7413XXZG</tt></t>
+ <t>Donor hash <tt>H</tt> = <tt>SHA-512( UTF-8(taxid) || 0x00 || UTF-8(salt) || 0x00 )</tt>:<br/>
+ - length: 64 bytes<br/>
+ - hex:<br/>
+<tt>4aaa1e16fc5be44842b863b1f17da39296ca7b3529a720e11aba9c8bd729f7a1e2bb0b9a39c02d271da5dd15aea66ce95be78bcaf380de19a0bdbcd8a7938f1b</tt><br/>
+ - Crockford Base32 (for HTTP endpoints):<br/>
+<tt>9AN1W5QWBFJ4GGNRCERZ2ZD3JABCMYSN56KJ1R8TQAE8QNS9YYGY5ERBK8WW0B973PJXT5DEMSPEJPZ7HF5F706Y36GBVF6RMY9RY6R</tt></t>
+ <t>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></t>
+ <t>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>: donor hash <tt>H</tt><br/>
+ - [0096..0099] 4 bytes <tt>year</tt>: <tt>0x000007E9</tt> (2025)</t>
+ <t>Message <tt>M</tt> (hex, 100 bytes):<br/>
+<tt>00000064 000005dc 0000000000000001 00000000 544553544b55444f53000000 4aaa1e16fc5be44842b863b1f17da39296ca7b3529a720e11aba9c8bd729f7a1e2bb0b9a39c02d271da5dd15aea66ce95be78bcaf380de19a0bdbcd8a7938f1b 000007e9</tt></t>
+ <t>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></t>
+ <t>Public key (Ed25519, Crockford Base32 -> bytes):<br/>
+ - length: 32 bytes<br/>
+ - hex:<br/>
+<tt>13f15131534b68de38253f0d1f24f856f3607d8c6011d4d4d268a9339023ef7f</tt></t>
+ <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>
+ <t>Negative check (optional): flip one bit of <tt>M</tt> or <tt>sig</tt> and repeat; verification MUST fail.</t>
+ </list>
+ </section>
+
+
+
+
+
+</middle>
+
+<back>
+
+ <references title="Normative References">
+
+ &RFC2119;
+
+ &RFC3986;
+
+ &RFC8174;
+
+ &RFC5234;
+
+ &RFC6234;
+
+ &RFC8032;
+
+ &RFC9498;
+
+ &RFC8905;
+
+
+ </references>
+
+ <references title="Informational References">
+
+ &RFC4648;
+
+
+ <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>
+
+<!-- Change Log
+v00 2025-10-17 CG Initial version
+v01 2025-10-21 EB Including first reviews (motivations + change in URI structure)
+ -->
+</back>
+</rfc>