donau

Donation authority for GNU Taler (experimental)
Log | Files | Refs | Submodules | README | LICENSE

implementation.tex (13260B)


      1 \section{Implementation}\label{implementation}
      2 
      3 This section describes the current implementation of the Donau, which
      4 consists of a REST API, an Android verification app, and the Donau
      5 database.  The Donau is written in C, as it reuses parts of the
      6 codebase from GNU Taler exchange component.  The Donau has a similar
      7 architecture and uses cryptographic blinded signatures in a similar
      8 way as the GNU Taler exchange does.
      9 
     10 On the user side, donation receipts are collected in a wallet; the
     11 wallet takes the users taxpayer ID and picks its own salt to create
     12 the Donor Identifier \DI.
     13 
     14 \subsection{REST API} \label{rest_api}
     15 
     16 The detailed REST API specification of the Donau back-end is publicly
     17 available under the following URL:
     18 \url{https://docs.taler.net/core/api-donau.html}. The following are
     19 the main API endpoints:
     20 
     21 \subsubsection{\texttt{/keys}}
     22 The \texttt{GET /keys} request returns all valid donation unit public keys
     23 offered by the Donau, as well as the Donau's current EdDSA public signing key.
     24 The following is an example response of a \texttt{curl 127.0.0.1:8080/keys}
     25 command. Some parts of the following example responses are truncated (denoted by
     26 the three dots '\texttt{...}') to make them more readable.
     27 
     28 \begin{verbatim}
     29 {
     30   "version": "0:0:0",
     31   "base_url": "http://localhost:8080/",
     32   "currency": "EUR",
     33   "signkeys": [
     34     {
     35       "stamp_start": {
     36         "t_s": 1717069556
     37       },
     38       "stamp_expire": {
     39         "t_s": 1718279156
     40       },
     41       "key": "CFV2PY8164E231XZSQK30K8R6CBQ..."
     42     },
     43     {
     44     ...
     45     }
     46     ],
     47     "donation_units": [
     48     {
     49       "donation_unit_pub": {
     50         "cipher": "RSA",
     51         "rsa_public_key": "020000YC7XK99S..."
     52       },
     53       "year": 2024,
     54       "lost": false,
     55       "value": "EUR:5"
     56     },
     57     {
     58       "donation_unit_pub": {
     59         "cipher": "CS",
     60         "cs_public_key": "7SKRQGBSEPBG24..."
     61       },
     62       "year": 2024,
     63       "lost": false,
     64       "value": "EUR:1"
     65     },
     66     {
     67     ...
     68     }
     69     ]
     70 }
     71 \end{verbatim}
     72 
     73 \subsubsection{\texttt{/charities}}
     74 
     75 In order for a charity to be able to issue receipts by a specific
     76 Donau it must be registered by this Donau.  The Donau provides an API
     77 to manage charities.  By default only the Donau administrator can
     78 change the list of registered charities.  The charity itself is able
     79 to request a donation report to keep track of their total donations in
     80 the current year.  The response includes the maximum donation amount
     81 and the current donated amount for the charity of the current year.
     82 
     83 \begin{figure}[ht]
     84 \includegraphics[width=0.5\textwidth]{donau_flow_register_charity}
     85 \caption{The tax authority registers a new charity in the Donau.
     86   A charity first requests to be added to the Donau, including its Charity EdDSA public key in its request.
     87   The tax authority them adds the charity by sending a POST request to the {\tt
     88 /charities} endpoint with the relevant data on the charity
     89 }\label{fig:donau_flow_register_charity}
     90 \end{figure}
     91 
     92 The following is an example response of a \texttt{curl 127.0.0.1:8080/charities} command.
     93 There is only one charity named \texttt{example} registered with a donation limit of 10 euros.
     94 
     95 \begin{verbatim}
     96 {
     97   "charities": [
     98     {
     99       "charity_pub": "ABETNXT9ZF606FRF3WD5...",
    100       "url": "example.com",
    101       "name": "example",
    102       "max_per_year": "EUR:10",
    103       "receipts_to_date": "EUR:0",
    104       "current_year": 2024
    105     }
    106   ]
    107 }
    108 \end{verbatim}
    109 
    110 To insert a charity a \texttt{POST} request can be sent using
    111 \texttt{curl -d @charity.json -X POST http://127.0.0.1:8080/charities}.
    112 
    113 The following is an example of a
    114 \texttt{charity.json} entry
    115 
    116 \begin{verbatim}
    117 {
    118   "charity_pub": "ABETNXT9ZF606FRF3WD5...",
    119   "charity_name": "mycharity",
    120   "charity_url": "mycharity.example.com",
    121   "max_per_year": "EUR:1000",
    122   "receipts_to_date": "EUR:0",
    123   "current_year": 2024
    124 }
    125 \end{verbatim}
    126 
    127 The response consists of the charity ID generated by the database.
    128 \begin{verbatim}
    129 {
    130   "charity-id": 1
    131 }
    132 \end{verbatim}
    133 
    134 
    135 \subsubsection{\texttt{/batch-issue}}
    136 Only recognized charities are allowed to issue receipts for their donors.
    137 A \texttt{POST} issue receipt request includes an array of \texttt{BKP}s. A
    138 \texttt{BKP} consists of a \texttt{BUDI} and a hash of a public donation unit
    139 key (see section~\ref{notation_and_definitions}).
    140 The charity signs the request with its own EdDSA private key. The
    141 corresponding public key was given to the Donau in the registration process of
    142 the charity.
    143 After the Donau checks the signature from the charity it signs the
    144 \texttt{BUDI}s with the corresponding donation unit private key. Before the
    145 signatures are returned to the charity the Donau saves a hash of the request
    146 and all donation unit signatures to detect replays (see section~\ref{donau_database}).
    147 
    148 \begin{figure}[ht]
    149 \includegraphics[width=0.5\textwidth]{donau_flow_issue_receipt}
    150 \caption{Flow of the issue receipt process} \label{fig:donau_flow_issue_receipt}
    151 \end{figure}
    152 
    153 The following is an example response of a \\
    154 \texttt{curl -d @issue.json -X POST http://127.0.0.1:8080/batch-issue/1}
    155 request showing a \texttt{issue.json} entry.
    156 The number at the end of the URL is the charity ID.
    157 
    158 
    159 
    160 \begin{verbatim}
    161 {
    162   "budikeypairs": [
    163   {
    164     "h_donaton_unit_pub": "130C2KDHTAFDQFB8XED...",
    165     "blinded_udi": {
    166     "cipher": "RSA",
    167     "rsa_blinded_identifier": "AXPTEE24W28S9XN..."
    168     }
    169   }
    170   ],
    171     "charity_sig": "JEJ0QMDXD416XKSK1SG0DETJEH...",
    172   "year": 2024
    173 }
    174 \end{verbatim}
    175 
    176 \begin{verbatim}
    177 {
    178    "blind_signatures": [
    179      {
    180       "blinded_signature": {
    181       "cipher": "RSA",
    182       "blinded_rsa_signature": "16XHNWSCDRVKHF..."
    183        }
    184      }
    185    ],
    186    "issued_amount: "EUR:15"
    187 }
    188 \end{verbatim}
    189 
    190 \subsubsection{\texttt{/batch-submit}}
    191 The batch-submit route is used by the donor to summarize their donation
    192 receipts into one donation statement, which then gets signed by the Donau with
    193 their EdDSA signature.
    194 The request is composed of the donation receipts (see section~\ref{donau_creates_donation_receipt}),
    195 the corresponding year and the Donor Identification \DI, which is the salted hash of the donor's taxpayer ID.
    196 When processing the request, the Donau checks the validity of the donation
    197 receipts and searches its database for other saved donation receipts made in the requested
    198 year.
    199 The Donau computes
    200 a donation statement, consisting of a signature over
    201 the total value of the donation units of all donation receipts of the year,
    202 the salted hash of the taxpayer ID, and the current year,
    203 and stores this in its database along with the submitted receipts (see section~\ref{donau_database}).
    204 
    205 In our implementation the Donau does not return this donation statement under
    206 this call but under the {\tt donation-statement} request, see below.
    207 
    208 The following is an example of a \\
    209 \texttt{curl -d @submit.json -X POST http://127.0.0.1:8080/batch-submit}
    210 request. If successful, the Donau returns the \texttt{HTTP 201} status code
    211 with an empty response.
    212 The following record would be stored.
    213 
    214 \begin{verbatim}
    215 {
    216   "h_donor_tax_id": "N2NYR2SFNGZSS388R2SB0VK...",
    217   "donation_year": 2024,
    218   "donation_receipts": [
    219   {
    220     "h_donaton_unit_pub": "130C2KDHTAFDQFB8X...",
    221     "nonce": "JEQC39G",
    222     "donation_unit_sig":
    223     {
    224     "cipher": "RSA",
    225     "rsa_signature":  "GQBXPNE4JT5W53T3CVP6E..."
    226     }
    227   }
    228   ]
    229 }
    230 \end{verbatim}
    231 
    232 \subsubsection{\texttt{/donation-statement}}
    233 To obtain the donation statement, the donor submits a GET request for a specified year and taxpayer ID.
    234 
    235 The following is an example response of a \\
    236 \texttt{curl http://127.0.0.1:8080/donation-statement/2024/N2NYR2SFNGZSS388R2SB...} \\
    237 request.
    238 
    239 The last parameter of the URL is the \DI.
    240 
    241 \begin{verbatim}
    242 {
    243   "total": "EUR:15",
    244   "donation_statement": "C1JVDP25AR001W5AHMAZ...",
    245   "donau_pub": "63f62b7901311c2187bfcde6304d1..."
    246 }
    247 \end{verbatim}
    248 
    249 \begin{figure}[ht]
    250 \includegraphics[width=0.5\textwidth]{donau_flow_submit_receipt}
    251 \caption{Donor requests a donation statement from the Donau} \label{fig:donau_flow_submit_receipt}
    252 \end{figure}
    253 
    254 \subsection{Donau client}
    255 The REST client removes some of the complexity of sending requests to the Donau
    256 server. It converts request parameters into JSON and parses JSON responses into
    257 a usable format.
    258 
    259 \subsection{Donau database}\label{donau_database}
    260 The Donau database contains five tables as shown in figure~\ref{fig:db_physical_model}.
    261 The \texttt{donation\_units} and
    262 \texttt{donau\_sign\_keys} table store the keys necessary for signing and
    263 creating donation receipts. Donation receipts that are issued to be signed by
    264 the donau are stored in the \texttt{receipts\_issued} table while the receipts
    265 that are already signed are stored in the \texttt{receipts\_submitted} table.
    266 The \texttt{history} table keeps the donation records of the past years.
    267 
    268 \begin{figure}[ht]
    269 \includegraphics[width=0.5\textwidth]{db_physical_model}
    270 \caption{Donau database model (generated by \url{https://dbdiagram.io/})} \label{fig:db_physical_model}
    271 \end{figure}
    272 \subsubsection{\tt charities}
    273 Each registered charity has an entry in this table. There may be a donation
    274 limit imposed by local law which prevents further donations if the limit is
    275 reached.
    276 
    277 \begin{itemize}
    278     \item \texttt{charity\_id:} Unique ID generated by the database.
    279     \item \texttt{charity\_pub:} Charity EdDSA public key
    280     \item \texttt{charity\_name:} Name of the charity
    281     \item \texttt{charity\_url:} Charity URL
    282     \item \texttt{max\_per\_year:} The annual donation limit according to local law.
    283     \item \texttt{receipts\_to\_date:} The current amount of donations in the current year. Reset to 0 when incrementing the \texttt{current\_year}.
    284     \item \texttt{current\_year:} Current year
    285 \end{itemize}
    286 
    287 \subsubsection{\tt donation\_units}
    288 Table containing all the valid donation units the Donau knows about.
    289 \begin{itemize}
    290     \item \texttt{donation\_unit\_serial:} Unique ID generated by the database.
    291     \item \texttt{h\_donation\_unit\_pub:} Hash value of the donation unit public key \texttt{donation\_unit\_pub}
    292     \item \texttt{donation\_unit\_pub:} The donation unit public key. Is either an RSA or Schnorr public key.
    293     \item \texttt{validity\_year:} The year, for which the donation unit is valid.
    294     \item \texttt{value:} The amount and currency that this donation unit represents.
    295 \end{itemize}
    296 
    297 \subsubsection{\tt donau\_sign\_keys}
    298 Contains all Donau EdDSA signing keys.
    299 \begin{itemize}
    300     \item \texttt{dsk\_serial:} Unique ID generated by the database.
    301     \item \texttt{donau\_pub:} Donau EdDSA public key.
    302     \item \texttt{valid\_from:} Year the signing key becomes valid.
    303     \item \texttt{expire\_sign:} Year the signing key becomes invalid.
    304     \item \texttt{expire\_legal:} Year the signing key legally expires.
    305 \end{itemize}
    306 
    307 \subsubsection{\tt receipts\_issued}
    308 Contains all issued donation receipts sent to the Donau.
    309 \begin{itemize}
    310     \item \texttt{receipt\_id:} Unique ID generated by the database.
    311     \item \texttt{blinded\_sig:} Array of blinded signatures. These are the \texttt{BKP}'s the Donau blind signed.
    312     \item \texttt{charity\_id:} The ID of the charity that received the donation.
    313     \item \texttt{receipt\_hash:} Hash value over all the blinded donation receipt received plus the hash of the donation units public key.
    314     \item \texttt{amount:} The amount and currency this donation receipt contains.
    315 \end{itemize}
    316 
    317 \subsubsection{\tt receipts\_submitted}
    318 Contains all submitted donation receipts sent to the Donor. By storing the
    319 signature \texttt{donation\_unit\_sig}, the idempotence of the API is kept in
    320 case the private key is replaced.
    321 \begin{itemize}
    322     \item \texttt{receipt\_id:} Unique ID generated by the database.
    323     \item \texttt{h\_tax\_number:} The hash of the tax number and salt (called
    324 $\DI$ in Section~\ref{technical}).
    325     \item \texttt{nonce:} The nonce used in the \texttt{Unique Donor Identifier}
    326     \item \texttt{donation\_unit\_pub:} Reference to public key used to sign.
    327     \item \texttt{donation\_unit\_sig:} The unblinded signature the Donau made.
    328     \item \texttt{donation\_year:} The year the donation was made.
    329 \end{itemize}
    330 
    331 \subsubsection{\tt history}
    332 History of the yearly donations for each charity. This data provides a record
    333 of donations each year. It could also provide valuable information that could
    334 be used in statistics to analyze general donations over the year.
    335 \begin{itemize}
    336     \item \texttt{charity\_id:} Unique ID generated by the database.
    337     \item \texttt{final\_amount:} The final amount that was donated to the charity
    338     \item \texttt{donation\_year:} The year in which the donations where made.
    339 \end{itemize}
    340 
    341 \subsection{Android Verification App}\label{android_verification_app}
    342 The Android app is part of the verification process used by the tax authority
    343 to check the donation statement (see
    344 section~\ref{donor_sends_final_statement_to_a_validator}).
    345 The app decodes the submitted QR code from the donor,
    346 parses the signed values and the signature,
    347 and uses them to verify the signature.
    348 The arguments of the QR code are defined in section~\ref{donor_sends_final_statement_to_a_validator}
    349 and encoded as colon-delimited base64 values:
    350 
    351 \begin{verbatim}
    352     YEAR:TOTALAMOUNT:TAXID:TAXIDSALT:ED25519SIGNATURE
    353 \end{verbatim}
    354 
    355 Finally, the values and the verification result are displayed.