commit 8c3e2849c2291d4abdb3024a66994c302fef2c21
parent a47e9aeb7e598178c291325bbd0624e7bf284ab1
Author: Bohdan Potuzhnyi <bohdan.potuzhnyi@gmail.com>
Date: Thu, 9 Oct 2025 00:35:29 +0200
updating some rfc refs + sha256 -> sha256 + clarification for the signature format + update of the test vector(a bit cleaner + sha512)
Diffstat:
| M | draft-donau.xml | | | 144 | +++++++++++++++++++++++++++++++++++++++---------------------------------------- |
1 file changed, 71 insertions(+), 73 deletions(-)
diff --git a/draft-donau.xml b/draft-donau.xml
@@ -233,7 +233,7 @@
<t>
Finally, algo specifies the specific signature algorithm
used; for now,
- only ED25519 (see <xref target="RFC7748" />) is supported.
+ 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
@@ -415,10 +415,10 @@ Example, a response to a GET request to the /key/ endpoint.
verification app MUST download them from the /donation-statement/
endpoint of the base.<br/>
- The verification app will compute the donor hash H using SHA256 <xref target="RFC6234"/>
+ 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-256(taxid || 0x00 || salt || 0x00)</tt>. Here, <tt>taxid</tt> is the
+ <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 hash-donor-id. The verification app will contact the
base in the endpoint /donation-statement with the year and the hash-donor-id.
@@ -503,24 +503,19 @@ Example of an element of USD 100.00 :
target="get-donation-statement"/>. Otherwise, it SHOULD use the
value given in the URI.
- The verification of the signature is done using EdDSA which was
- presented in <xref target="RFC7748" />.
+ 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 data to be confirmed is composed of the following information:
+ 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>The size of the confirmation to verify written
- in the network order on an 32-bit unsigned integer.</li>
- <li>The value 1500 written
- in the network order on an 32-bit unsigned integer.</li>
- <li>The total number is written in three fields. First, the integer part of the value represented on 64-bit unsigned integer in big endian. Then comes the fractional part of the total value represented by a unsigned integer on 32 bit (also big endian) representing the number of 1/100000000th of the base unit. The third part is a 12-byte string (terminating with the 0x00 character) representing the currency of the total value.</li>
- <li>The year on a 64 bit long unsigned integer in network order.</li>
- <li>The SHA256 donor hash H computed as
- <tt>H = SHA-256(taxid || 0x00 || salt || 0x00)</tt>, where all strings are
- UTF-8 encoded and <tt>0x00</tt> denotes a single NUL byte separator.</li>
- <li>The SHA256 hash code for the donor ID (i.e., H).</li>
+ <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>
@@ -557,7 +552,7 @@ Example of an element of USD 100.00 :
+-----+-----+-----+-----+ +
| |
+-----+-----+-----+-----+-----+-----+-----+-----+
-| SHA256 of the donor ID |
+| SHA512 of the donor ID |
/ /
/ /
+-----+-----+-----+-----+-----+-----+-----+-----+
@@ -588,13 +583,12 @@ Example of an element of USD 100.00 :
<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>
+ <dt>TOTAL currency</dt>
<dd>
- A string representing the currency. 12 bytes for the currency as an string. The last byte
- must be a 0-terminator.
+ A string representing the currency. ASCII, left-aligned and zero-padded to exactly 12 bytes.
</dd>
<dt>HASH:</dt>
- <dd>The SHA256 hash code for the donor ID.</dd>
+ <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>
@@ -679,64 +673,68 @@ Value Encoding Value Encoding Value Encoding Value Encoding
<figure>
<artwork><![CDATA[
Example URI:
-donau://example.com/megacharity/1234/2025/7560001010000/1234?total=EUR:15&sig=ED25519:H9PM3BW3P8MEKB34GZ0G1F7JSNVX7B8AHXRFFMS37QZM7TXZ5MWPXTEDZZGN1QRB1AFPKNCFXJB39NJHP3BAFGCZSCXHEYPHA1YJY28
+donau://donau.test.taler.net/2025/123%2F456%2F789/AWNFDRFT0WX45W4Y32A9DJA03S1EF66GFQZ9EV5EF9JTHWZ37WR0?total=TESTKUDOS:1&sig=ED25519:B14WGS43FFPEB8JMSR6W1H8M6KH9AV33JFH376R6PM2MNH4GR24FP1C93C4ZPDG21W5WY4SASZQ4CRS427F4WJZJFZMQ5Y4HZNXGY30
Extracted fields:
-- base: example.com/megacharity/1234
+- base: donau.test.taler.net
- year: 2025
-- taxid: 7560001010000
-- salt: 1234
-- total: EUR:15
-- signature: ED25519:H9PM3BW3P8MEKB34GZ0G1F7JSNVX7B8AHXRFFMS37QZM7TXZ5MWPXTEDZZGN1QRB1AFPKNCFXJB39NJHP3BAFGCZSCXHEYPHA1YJY28
-
-Fetched public key for year 2025 from https://example.com/megacharity/1234/keys:
-- pub (Base32 Crockford): K641W1CZM7DRSV184M8CPM3Z8MZRBYYJMNYMJK70FTYJHBPX21J0
+- 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>
- Decode the public key from Base32 (Crockford) to 32 bytes. Accept
- OCR-normalized characters as defined in <xref target="base32-U-crockford"/>.
- Decoded public key (hex):
- <tt>99881e059fa1db8cec282510cb507f453f85fbd2a57d494ce07ebd28aedd1064</tt>.
- </t>
- <t>
- Normalize and decode the signature: remove the <tt>ED25519:</tt> prefix, then
- decode the remainder using Base32 (Crockford) to 64 bytes.
- Decoded signature (hex):
- <tt>8a6d41af83b228e9ac6487c100bcf2cd77d3ad0a8f70f7d3233dff43ebbf2d396ee9cdffe150df0b0a9f69d58fec9634d651b0d6a7c19fcb3b177ad1507d2f09</tt>.
- </t>
- <t>
- Compute the donor hash H from the exact UTF-8 bytes of <tt>taxid</tt>,
- a NUL separator (0x00), then <tt>salt</tt>, then a final NUL (0x00):
- <tt>SHA-256("7560001010000" || 0x00 || "1234" || 0x00)</tt> =
- <tt>09fbc815d838c845f147dc90fbc3ae6455d050f238239dd3e9141dc461e4dc8c</tt> (hex).
- When requesting the donation statement, encode H with Base32 (Crockford)
- for the URL path.
- </t>
- <t>
- Construct the signed payload bytes in network byte order (big endian)
- using the following field sequence:
- <figure><artwork><![CDATA[
-SIZE (4 bytes): 0x00000044 (total payload length = 68)
-PURPOSE (4 bytes): 0x000005DC (decimal 1500)
-AMOUNT (8+4+12): value=15 (0x000000000000000F), fraction=0 (0x00000000), currency="EUR" + 9x 0x00
-DONOR HASH (32 B): H = SHA-256(taxid || 0x00 || salt || 0x00)
-YEAR (4 bytes): 0x000007E9 (2025)
- ]]></artwork></figure>
- Complete payload (hex):
- <figure><artwork><![CDATA[
-00000044000005dc000000000000000f0000000045555200000000000000000009fbc815d838c845f147dc90fbc3ae6455d050f238239dd3e9141dc461e4dc8c000007e9
- ]]></artwork></figure>
- </t>
- <t>
- Verify the Ed25519 detached signature over the payload using the decoded
- public key. For example, with libsodium:
- <tt>crypto_sign_verify_detached(signature, payload, payload_len, public_key)</tt>.
- The verification returns success for this example.
- </t>
+ <t>Input (URI):<br/>
+<tt>donau://donau.test.taler.net/2025/123%2F456%2F789/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>