lsd0013

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

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:
Adraft-grothoff-donau-01.xml | 835+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
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&ouml;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&ouml;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&ouml;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&amp;id=123%2F456%2F789&amp;salt=AWNFDRFT0WX45W4Y32A9DJA03S1EF66GFQZ9EV5EF9JTHWZ37WR0&amp;total=TESTKUDOS:1&amp;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>