draft-guetschow-taler-protocol.xml (82081B)
1 <?xml version='1.0' encoding='utf-8'?> 2 <!DOCTYPE rfc [ 3 <!ENTITY nbsp " "> 4 <!ENTITY zwsp "​"> 5 <!ENTITY nbhy "‑"> 6 <!ENTITY wj "⁠"> 7 ]> 8 <?xml-stylesheet type="text/xsl" href="rfc2629.xslt" ?> 9 <!-- generated by https://github.com/cabo/kramdown-rfc version 1.7.35 (Ruby 3.1.2) --> 10 <rfc xmlns:xi="http://www.w3.org/2001/XInclude" ipr="trust200902" docName="draft-guetschow-taler-protocol" category="info" submissionType="independent" tocInclude="true" sortRefs="true" symRefs="true" version="3"> 11 <!-- xml2rfc v2v3 conversion 3.32.0 --> 12 <front> 13 <title>The GNU Taler Protocol</title> 14 <seriesInfo name="Internet-Draft" value="draft-guetschow-taler-protocol"/> 15 <author initials="M." surname="Gütschow" fullname="Mikolai Gütschow"> 16 <organization abbrev="TU Dresden">TUD Dresden University of Technology</organization> 17 <address> 18 <postal> 19 <street>Helmholtzstr. 10</street> 20 <city>Dresden</city> 21 <code>D-01069</code> 22 <country>Germany</country> 23 </postal> 24 <email>mikolai.guetschow@tu-dresden.de</email> 25 </address> 26 </author> 27 <date year="2026" month="April" day="30"/> 28 <workgroup>independent</workgroup> 29 <keyword>taler</keyword> 30 <keyword>cryptography</keyword> 31 <keyword>ecash</keyword> 32 <keyword>payments</keyword> 33 <abstract> 34 <?line 45?> 35 36 <t>[ TBW ]</t> 37 </abstract> 38 </front> 39 <middle> 40 <?line 49?> 41 42 <section anchor="introduction"> 43 <name>Introduction</name> 44 <t>[ TBW ]</t> 45 <t>Beware that this document is still work-in-progress and may contain errors. 46 Use at your own risk!</t> 47 </section> 48 <section anchor="notation"> 49 <name>Notation</name> 50 <ul spacing="normal"> 51 <li> 52 <t><tt>"abc"</tt> denotes the literal string <tt>abc</tt> encoded as ASCII <xref target="RFC20"/></t> 53 </li> 54 <li> 55 <t><tt>a | b</tt> denotes the concatenation of a with b</t> 56 </li> 57 <li> 58 <t><tt>len(a)</tt> denotes the length in bytes of the byte string a</t> 59 </li> 60 <li> 61 <t><tt>padZero(y, a)</tt> denotes the byte string a, zero-padded to the length of y bytes</t> 62 </li> 63 <li> 64 <t><tt>bits(x)</tt>/<tt>bytes(x)</tt> denotes the minimal number of bits/bytes necessary to represent the multiple precision integer x</t> 65 </li> 66 <li> 67 <t><tt>uint(y, x)</tt> denotes the <tt>y</tt> least significant bits of the integer <tt>x</tt>, zero-padded and encoded in network byte order (big endian)</t> 68 </li> 69 <li> 70 <t><tt>uintY(x)</tt> where <tt>Y</tt> is a positive integer number is equivalent to <tt>uint(Y, x)</tt></t> 71 </li> 72 <li> 73 <t><tt>random(y)</tt> denotes a randomly generated sequence of y bits</t> 74 </li> 75 <li> 76 <t><tt>a * b (mod N)</tt> / <tt>a ** b (mod N)</tt> denotes the multiplication / exponentiation of multiple precision integers a and b, modulo N</t> 77 </li> 78 <li> 79 <t><tt>for</tt>, <tt>if</tt>, variable assignment <tt>=</tt>, and conditional operators are to be interpreted like their Python/Julia equivalents</t> 80 </li> 81 <li> 82 <t><tt>data.key</tt> denotes the property <tt>key</tt> on the object <tt>data</tt></t> 83 </li> 84 <li> 85 <t><tt>0..n</tt> denotes the exclusive range of integer numbers from <tt>0</tt> to <tt>n</tt>, i.e., <tt>0, 1, 2, ..., n-1</tt></t> 86 </li> 87 <li> 88 <t><tt>⟨dataᵢ⟩</tt> within a context of <tt>i = 0..n</tt> denotes <tt>n</tt> objects <tt>dataᵢ</tt>, represented in memory as a continuous array</t> 89 </li> 90 <li> 91 <t><tt>⟨dataᵢ.key⟩</tt> within a context of <tt>i = 0..n</tt> denotes an array of the <tt>n</tt> properties <tt>key</tt> of all <tt>n</tt> objects <tt>dataᵢ</tt></t> 92 </li> 93 </ul> 94 </section> 95 <section anchor="cryptographic-primitives"> 96 <name>Cryptographic Primitives</name> 97 <t>// todo: maybe change this description to something more similar to protocol functions (Julia-inspired syntax)</t> 98 <section anchor="cryptographic-hash-functions"> 99 <name>Cryptographic Hash Functions</name> 100 <section anchor="sha256"> 101 <name>SHA-256</name> 102 <artwork><![CDATA[ 103 SHA-256(msg) -> hash 104 105 Input: 106 msg input message of length L < 2^61 octets 107 108 Output: 109 hash message digest of fixed length HashLen = 32 octets 110 ]]></artwork> 111 <t><tt>hash</tt> is the output of SHA-256 as per Sections 4.1, 5.1, 6.1, and 6.2 of <xref target="RFC6234"/>.</t> 112 </section> 113 <section anchor="sha512"> 114 <name>SHA-512</name> 115 <artwork><![CDATA[ 116 SHA-512(msg) -> hash 117 118 Input: 119 msg input message of length L < 2^125 octets 120 121 Output: 122 hash message digest of fixed length HashLen = 64 octets 123 ]]></artwork> 124 <t><tt>hash</tt> is the output of SHA-512 as per Sections 4.2, 5.2, 6.3, and 6.4 of <xref target="RFC6234"/>.</t> 125 </section> 126 <section anchor="sha512-trunc"> 127 <name>SHA-512-256 (truncated SHA-512)</name> 128 <artwork><![CDATA[ 129 SHA-512-256(msg) -> hash 130 131 Input: 132 msg input message of length L < 2^125 octets 133 134 Output: 135 hash message digest of fixed length HashLen = 32 octets 136 ]]></artwork> 137 <t>The output <tt>hash</tt> corresponds to the first 32 octets of the output of SHA-512 defined in <xref target="sha512"/>:</t> 138 <artwork><![CDATA[ 139 temp = SHA-512(msg) 140 hash = temp[0:31] 141 ]]></artwork> 142 <t>Note that this operation differs from SHA-512/256 as defined in <xref target="SHS"/> in the initial hash value.</t> 143 </section> 144 </section> 145 <section anchor="message-authentication-codes"> 146 <name>Message Authentication Codes</name> 147 <section anchor="hmac"> 148 <name>HMAC</name> 149 <artwork><![CDATA[ 150 HMAC-Hash(key, text) -> out 151 152 Option: 153 Hash cryptographic hash function with output length HashLen 154 155 Input: 156 key secret key of length at least HashLen 157 text input data of arbitary length 158 159 Output: 160 out output of length HashLen 161 ]]></artwork> 162 <t><tt>out</tt> is calculated as defined in <xref target="RFC2104"/>.</t> 163 </section> 164 </section> 165 <section anchor="key-derivation-functions"> 166 <name>Key Derivation Functions</name> 167 <section anchor="hkdf"> 168 <name>HKDF</name> 169 <t>The Hashed Key Derivation Function (HKDF) used in Taler is an instantiation of <xref target="RFC5869"/> 170 with two different hash functions for the Extract and Expand step as suggested in <xref target="HKDF"/>: 171 <tt>HKDF-Extract</tt> uses <tt>HMAC-SHA512</tt>, while <tt>HKDF-Expand</tt> uses <tt>HMAC-SHA256</tt> (cf. <xref target="hmac"/>).</t> 172 <artwork><![CDATA[ 173 HKDF(salt, IKM, info, L) -> OKM 174 175 Inputs: 176 salt optional salt value (a non-secret random value); 177 if not provided, it is set to a string of 64 zeros. 178 IKM input keying material 179 info optional context and application specific information 180 (can be a zero-length string) 181 L length of output keying material in octets 182 (<= 255*32 = 8160) 183 184 Output: 185 OKM output keying material (of L octets) 186 ]]></artwork> 187 <t>The output OKM is calculated as follows:</t> 188 <artwork><![CDATA[ 189 PRK = HKDF-Extract(salt, IKM) with Hash = SHA-512 (HashLen = 64) 190 OKM = HKDF-Expand(PRK, info, L) with Hash = SHA-256 (HashLen = 32) 191 ]]></artwork> 192 </section> 193 <section anchor="hkdf-mod"> 194 <name>HKDF-Mod</name> 195 <t>Based on the HKDF defined in <xref target="hkdf"/>, this function returns an OKM that is smaller than a given multiple precision integer N.</t> 196 <artwork><![CDATA[ 197 HKDF-Mod(N, salt, IKM, info) -> OKM 198 199 Inputs: 200 N multiple precision integer 201 salt optional salt value (a non-secret random value); 202 if not provided, it is set to a string of 64 zeros. 203 IKM input keying material 204 info optional context and application specific information 205 (can be a zero-length string) 206 207 Output: 208 OKM output keying material (smaller than N) 209 ]]></artwork> 210 <t>The final output <tt>OKM</tt> is determined deterministically based on a counter initialized at zero.</t> 211 <artwork><![CDATA[ 212 counter = 0 213 do until OKM < N: 214 x = HKDF(salt, IKM, info | uint16(counter), bytes(N)) 215 OKM = uint(bits(N), x) 216 counter += 1 217 ]]></artwork> 218 </section> 219 </section> 220 <section anchor="non-blind-signatures"> 221 <name>Non-Blind Signatures</name> 222 <section anchor="ed25519"> 223 <name>Ed25519</name> 224 <t>Taler uses EdDSA instantiated with curve25519 as Ed25519, 225 as defined in Section 5.1 of <xref target="RFC8032"/>. 226 In particular, Taler does <em>not</em> make use of Ed25519ph or Ed25519ctx 227 as defined in that document.</t> 228 <section anchor="key-generation"> 229 <name>Key generation</name> 230 <artwork><![CDATA[ 231 Ed25519-GetPub(priv) -> pub 232 233 Input: 234 priv private Ed25519 key 235 236 Output: 237 pub public Ed25519 key 238 ]]></artwork> 239 <t><tt>pub</tt> is calculated as described in Section 5.1.5 of <xref target="RFC8032"/>.</t> 240 <artwork><![CDATA[ 241 Ed25519-Keygen() -> (priv, pub) 242 243 Output: 244 priv private Ed25519 key 245 pub public Ed25519 key 246 ]]></artwork> 247 <t><tt>priv</tt> and <tt>pub</tt> are calculated as described in Section 5.1.5 of <xref target="RFC8032"/>, 248 which is equivalent to the following:</t> 249 <artwork><![CDATA[ 250 priv = random(256) 251 pub = Ed25519-GetPub(priv) 252 ]]></artwork> 253 </section> 254 <section anchor="signing"> 255 <name>Signing</name> 256 <artwork><![CDATA[ 257 Ed25519-Sign(priv, msg) -> sig 258 259 Inputs: 260 priv Ed25519 private key 261 msg message to be signed 262 263 Output: 264 sig signature on the message by the given private key 265 ]]></artwork> 266 <t><tt>sig</tt> is calculated as described in Section 5.1.6 of <xref target="RFC8032"/>.</t> 267 </section> 268 <section anchor="verifying"> 269 <name>Verifying</name> 270 <artwork><![CDATA[ 271 Ed25519-Verify(pub, msg, sig) -> out 272 273 Inputs: 274 pub Ed25519 public key 275 msg signed message 276 sig signature on msg 277 278 Output: 279 out true, if sig is a valid signature for msg 280 ]]></artwork> 281 <t><tt>out</tt> is the outcome of the last check of Section 5.1.7 of <xref target="RFC8032"/>.</t> 282 </section> 283 </section> 284 </section> 285 <section anchor="key-agreement"> 286 <name>Key Agreement</name> 287 <section anchor="x25519"> 288 <name>X25519</name> 289 <t>Taler uses Elliptic Curve Diffie-Hellman (ECDH) on curve25519 as defined in Section 6.1 of <xref target="RFC7748"/>, 290 but reuses Ed25519 keypairs for one side of the agreement instead of random bytes. 291 Depending on whether the private or public part is from Ed25519, two different functions are used.</t> 292 <artwork><![CDATA[ 293 ECDH-Ed25519-Priv(priv, pub) -> shared 294 295 Input: 296 priv private Ed25519 key 297 pub public X25519 key 298 299 Output: 300 shared shared secret based on the given keys 301 ]]></artwork> 302 <t><tt>shared</tt> is calculated as follows, using the function X25519 defined in Section 5 of <xref target="RFC7748"/>:</t> 303 <artwork><![CDATA[ 304 priv' = SHA-512-256(priv) 305 // todo: missing bit clamping from https://github.com/jedisct1/libsodium/blob/master/src/libsodium/crypto_sign/ed25519/ref10/keypair.c#L71 306 shared' = X25519(priv', pub) 307 shared = SHA-512(shared') 308 ]]></artwork> 309 <artwork><![CDATA[ 310 ECDH-Ed25519-Pub(priv, pub) -> shared 311 312 Input: 313 priv private X25519 key 314 pub public Ed25519 key 315 316 Output: 317 shared shared secret based on the given keys 318 ]]></artwork> 319 <t><tt>shared</tt> is calculated as follows, using the function X25519 defined in Section 5 of <xref target="RFC7748"/>, 320 and <tt>Convert-Point-Ed25519-Curve25519(p)</tt> which implements the birational map of Section 4.1 of <xref target="RFC7748"/>:</t> 321 <artwork><![CDATA[ 322 pub' = Convert-Point-Ed25519-Curve25519(pub) 323 shared' = X25519(priv, pub') 324 shared = SHA-512(shared') 325 ]]></artwork> 326 <artwork><![CDATA[ 327 ECDH-GetPub(priv) -> pub 328 329 Input: 330 priv private X25519 key 331 332 Output: 333 pub public X25519 key 334 ]]></artwork> 335 <t><tt>pub</tt> is calculated according to Section 6.1 of <xref target="RFC7748"/>:</t> 336 <artwork><![CDATA[ 337 pub = X25519(priv, 9) 338 ]]></artwork> 339 </section> 340 </section> 341 <section anchor="blind-signatures"> 342 <name>Blind Signatures</name> 343 <section anchor="rsa-fdh"> 344 <name>RSA-FDH</name> 345 <section anchor="supporting-functions"> 346 <name>Supporting Functions</name> 347 <artwork><![CDATA[ 348 RSA-FDH(msg, pubkey) -> fdh 349 350 Inputs: 351 msg message 352 pubkey RSA public key consisting of modulus N and public exponent e 353 354 Output: 355 fdh full-domain hash of msg over pubkey.N 356 ]]></artwork> 357 <t><tt>fdh</tt> is calculated based on HKDF-Mod from <xref target="hkdf-mod"/> as follows:</t> 358 <artwork><![CDATA[ 359 info = "RSA-FDA FTpsW!" 360 salt = uint16(bytes(pubkey.N)) | uint16(bytes(pubkey.e)) 361 | pubkey.N | pubkey.e 362 fdh = HKDF-Mod(pubkey.N, salt, msg, info) 363 ]]></artwork> 364 <t>The resulting <tt>fdh</tt> can be used to test against a malicious RSA pubkey 365 by verifying that the greatest common denominator (gcd) of <tt>fdh</tt> and <tt>pubkey.N</tt> is 1.</t> 366 <artwork><![CDATA[ 367 RSA-FDH-Derive(bks, pubkey) -> out 368 369 Inputs: 370 bks blinding key secret of length L = 32 octets 371 pubkey RSA public key consisting of modulus N and public exponent e 372 373 Output: 374 out full-domain hash of bks over pubkey.N 375 ]]></artwork> 376 <t><tt>out</tt> is calculated based on HKDF-Mod from <xref target="hkdf-mod"/> as follows:</t> 377 <artwork><![CDATA[ 378 info = "Blinding KDF" 379 salt = "Blinding KDF extractor HMAC key" 380 fdh = HKDF-Mod(pubkey.N, salt, bks, info) 381 ]]></artwork> 382 </section> 383 <section anchor="blinding"> 384 <name>Blinding</name> 385 <artwork><![CDATA[ 386 RSA-FDH-Blind(msg, bks, pubkey) -> out 387 388 Inputs: 389 msg message 390 bks blinding key secret of length L = 32 octets 391 pubkey RSA public key consisting of modulus N and public exponent e 392 393 Output: 394 out message blinded for pubkey 395 ]]></artwork> 396 <t><tt>out</tt> is calculated based on RSA-FDH from <xref target="rsa-fdh"/> as follows:</t> 397 <artwork><![CDATA[ 398 data = RSA-FDH(msg, pubkey) 399 r = RSA-FDH-Derive(bks, pubkey) 400 r_e = r ** pubkey.e (mod pubkey.N) 401 out = r_e * data (mod pubkey.N) 402 ]]></artwork> 403 </section> 404 <section anchor="signing-1"> 405 <name>Signing</name> 406 <artwork><![CDATA[ 407 RSA-FDH-Sign(data, privkey) -> sig 408 409 Inputs: 410 data data to be signed, an integer smaller than privkey.N 411 privkey RSA private key consisting of modulus N and private exponent d 412 413 Output: 414 sig signature on data by privkey 415 ]]></artwork> 416 <t><tt>sig</tt> is calculated as follows:</t> 417 <artwork><![CDATA[ 418 sig = data ** privkey.d (mod privkey.N) 419 ]]></artwork> 420 </section> 421 <section anchor="unblinding"> 422 <name>Unblinding</name> 423 <artwork><![CDATA[ 424 RSA-FDH-Unblind(sig, bks, pubkey) -> out 425 426 Inputs: 427 sig blind signature 428 bks blinding key secret of length L = 32 octets 429 pubkey RSA public key consisting of modulus N and public exponent e 430 431 Output: 432 out unblinded signature 433 ]]></artwork> 434 <t><tt>out</tt> is calculated as follows:</t> 435 <artwork><![CDATA[ 436 r = RSA-FDH-Derive(bks, pubkey) 437 r_inv = inverse of r (mod pubkey.N) 438 out = sig * r_inv (mod pubkey.N) 439 ]]></artwork> 440 </section> 441 <section anchor="verifying-1"> 442 <name>Verifying</name> 443 <artwork><![CDATA[ 444 RSA-FDH-Verify(msg, sig, pubkey) -> out 445 446 Inputs: 447 msg message 448 sig signature of pubkey over msg 449 pubkey RSA public key consisting of modulus N and public exponent e 450 451 Output: 452 out true, if sig is a valid signature 453 ]]></artwork> 454 <t><tt>out</tt> is calculated based on RSA-FDH from <xref target="rsa-fdh"/> as follows:</t> 455 <artwork><![CDATA[ 456 data = RSA-FDH(msg, pubkey) 457 exp = sig ** pubkey.e (mod pubkey.N) 458 out = (data == exp) 459 ]]></artwork> 460 </section> 461 </section> 462 <section anchor="clause-schnorr"> 463 <name>Clause-Schnorr</name> 464 </section> 465 </section> 466 </section> 467 <section anchor="datatypes-and-notation"> 468 <name>Datatypes and Notation</name> 469 <section anchor="amounts"> 470 <name>Amounts</name> 471 <t>Amounts are represented in Taler as positive fixed-point values 472 consisting of <tt>value</tt> as the non-negative integer part of the base currency, 473 the <tt>fraction</tt> given in units of one hundred millionth (1e-8) of the base currency, 474 and <tt>currency</tt> as the 3-11 ASCII characters identifying the currency.</t> 475 <t>Whenever used in the protocol, the binary representation of an <tt>amount</tt> is 476 <tt>uint64(amount.value) | uint32(amount.fraction) | padZero(12, amount.currency)</tt>.</t> 477 </section> 478 <section anchor="timestamps"> 479 <name>Timestamps</name> 480 <t>Absolute timestamps are represented as <tt>uint64(x)</tt> where <tt>x</tt> corresponds to 481 the microseconds since <tt>1970-01-01 00:00 CEST</tt> (the UNIX epoch). 482 The special value <tt>0xFFFFFFFFFFFFFFFF</tt> represents "never". 483 <!-- 484 // todo: check if needed and correct 485 Relative timestamps are represented as `uint64(x)` where `x` is given in microseconds. 486 The special value `0xFFFFFFFFFFFFFFFF` represents "forever". 487 --> 488 </t> 489 </section> 490 <section anchor="signatures"> 491 <name>Signatures</name> 492 <t>All messages to be signed in Taler start with a header containing their size and 493 a fixed signing context (purpose) as registered by GANA in the 494 <eref target="https://gana.gnunet.org/gnunet-signatures/gnunet_signatures.html">GNUnet Signature Purposes</eref> 495 registry. Taler-related purposes start at 1000.</t> 496 <artwork><![CDATA[ 497 Gen-Msg(purpose, msg) -> out 498 499 Inputs: 500 purpose signature purpose as registered at GANA 501 msg message content (excl. header) to be signed 502 503 Output: 504 out complete message (incl. header) to be signed 505 ]]></artwork> 506 <t><tt>out</tt> is formed as follows:</t> 507 <artwork><![CDATA[ 508 out = uint32(len(msg)) | uint32(purpose) | msg 509 ]]></artwork> 510 </section> 511 <section anchor="helper-functions"> 512 <name>Helper Functions</name> 513 <t>There are a certain number of single-argument functions which are often needed, 514 and therefore omit the parentheses of the typical function syntax:</t> 515 <ul spacing="normal"> 516 <li> 517 <t><tt>Knows data</tt> specifies <tt>data</tt> that is known a priori at the start of the protocol operation</t> 518 </li> 519 <li> 520 <t><tt>Check cond</tt> verifies that the boolean condition or variable <tt>cond</tt> is true, 521 or aborts the protocol operation otherwise</t> 522 </li> 523 <li> 524 <t><tt>Persist data</tt> persists the given <tt>data</tt> to the local database</t> 525 </li> 526 <li> 527 <t><tt>data = Lookup by key</tt> retrieves previously persisted <tt>data</tt> by the given <tt>key</tt></t> 528 </li> 529 <li> 530 <t><tt>Sum ⟨dataᵢ⟩</tt> is valid for numerical objects <tt>dataᵢ</tt> including amounts (cf. <xref target="amounts"/>), 531 and denotes the numerical sum of these objects</t> 532 </li> 533 </ul> 534 <t>Some more functions that are commonly used throughout <xref target="protocol"/>:</t> 535 <artwork><![CDATA[ 536 Hash-Denom(denom) = 537 SHA-512(uint32(0) | uint32(1) | denom.pub) 538 539 Hash-Planchet(planchet, denom) = 540 SHA-512( SHA-512( denom.pub ) | uint32(0x1) | planchet ) 541 542 Check-Subtract(value, subtrahend) = 543 Check value >= subtrahend 544 Persist value -= subtrahend 545 ]]></artwork> 546 </section> 547 </section> 548 <section anchor="protocol"> 549 <name>The Taler Crypto Protocol</name> 550 <t>// todo: briefly introduce the three components wallet, exchange, merchant; maybe with ASCII diagram version</t> 551 <t>// todo: capitalize wallet, exchange, merchant?</t> 552 <section anchor="obtaining-e-cash"> 553 <name>Obtaining E-Cash</name> 554 <section anchor="withdraw"> 555 <name>Withdrawal</name> 556 <t>The wallet generates <tt>n > 0</tt> coins <tt>⟨coinᵢ⟩</tt> and requests <tt>n</tt> signatures <tt>⟨blind_sigᵢ⟩</tt> from the exchange, 557 attributing value to the coins according to <tt>n</tt> chosen denominations <tt>⟨denomᵢ⟩</tt>. 558 The total value and withdrawal fee (defined by the exchange per denomination) 559 must be smaller or equal to the amount stored in the single reserve used for withdrawal.</t> 560 <t>// todo: document TALER_MAX_COINS = 64 per operation (due to CS-encoding)</t> 561 <t>// todo: extend with extra roundtrip for CBS</t> 562 <artwork><![CDATA[ 563 wallet exchange 564 Knows ⟨denomᵢ⟩ Knows ⟨denomᵢ.priv⟩ 565 | | 566 +-----------------------------+ | 567 | (W1) reserve key generation | | 568 +-----------------------------+ | 569 | | 570 |----------- (bank transfer) ----------->| 571 | (subject: reserve.pub, amount: value) | 572 | | 573 | +------------------------------+ 574 | | Persist (reserve.pub, value) | 575 | +------------------------------+ 576 | | 577 +-----------------------------------+ | 578 | (W2) coin generation and blinding | | 579 +-----------------------------------+ | 580 | | 581 |-------------- /withdraw -------------->| 582 | (reserve.pub, planchets, sig) | 583 | | 584 | +--------------------------------+ 585 | | (E1) coin issuance and signing | 586 | +--------------------------------+ 587 | | 588 |<---------- (⟨blind_sigᵢ⟩) -------------| 589 | | 590 +----------------------+ | 591 | (W3) coin unblinding | | 592 +----------------------+ | 593 | | 594 ]]></artwork> 595 <t>where (for RSA, without age-restriction)</t> 596 <artwork><![CDATA[ 597 (W1) reserve key generation (wallet) 598 599 reserve = Ed25519-Keygen() 600 Persist (reserve, value) 601 ]]></artwork> 602 <t>The wallet derives coins and blinding secrets using a HKDF from a single seed per withdrawal operation, 603 together with an integer index. 604 This is strictly speaking an implementation detail since the seed is never revealed to any other party, 605 and might be chosen to be implemented differently.</t> 606 <t>// todo: blind_secret/coin.priv differently generated in TALER_EXCHANGE_post_withdraw_start/prepare_coins, double check with wallet-core (probably implementation detail here)</t> 607 <artwork><![CDATA[ 608 (W2) coin generation and blinding (wallet) 609 610 batch_seed = random(256) 611 Persist batch_seed 612 for i in 0..n: 613 coin_seedᵢ = HKDF(uint32(i), batch_seed, "taler-withdrawal-coin-derivation", 64) 614 blind_secretᵢ = coin_seedᵢ[32:] 615 coinᵢ.priv = coin_seedᵢ[:32] 616 coinᵢ.pub = Ed25519-GetPub(coinᵢ.priv) 617 h_denomᵢ = Hash-Denom(denomᵢ) 618 planchetᵢ = RSA-FDH-Blind(SHA-512(coinᵢ.pub), blind_secretᵢ, denomᵢ.pub) 619 h_planchetᵢ = Hash-Planchet(planchetᵢ, denomᵢ) 620 planchets = (⟨h_denomᵢ⟩, ⟨planchetᵢ⟩) 621 msg = Gen-Msg(WALLET_RESERVE_WITHDRAW, 622 ( Sum ⟨denomᵢ.value⟩ | Sum ⟨denomᵢ.fee_withdraw⟩ 623 | SHA-512( ⟨h_planchetᵢ⟩ ) | uint256(0x0) | uint32(0x0) | uint32(0x0) )) 624 sig = Ed25519-Sign(reserve.priv, msg) 625 ]]></artwork> 626 <artwork><![CDATA[ 627 (E1) coin issuance and signing (exchange) 628 629 (⟨h_denomᵢ⟩, ⟨planchetᵢ⟩) = planchets 630 for i in 0..n: 631 denomᵢ = Lookup by h_denomᵢ 632 Check denomᵢ known and not withdraw-expired 633 h_planchetᵢ = Hash-Planchet(planchetᵢ, denomᵢ) 634 msg = Gen-Msg(WALLET_RESERVE_WITHDRAW, 635 ( Sum ⟨denomᵢ.value⟩ | Sum ⟨denomᵢ.fee_withdraw⟩ 636 | SHA-512( ⟨h_planchetᵢ⟩ ) | uint256(0x0) | uint32(0x0) | uint32(0x0) )) 637 Check Ed25519-Verify(reserve.pub, msg, sig) 638 Check reserve KYC status ok or not needed 639 total = Sum ⟨denomᵢ.value⟩ + Sum ⟨denomᵢ.fee_withdraw⟩ 640 Check-Subtract(reserve.balance, total) 641 for i in 0..n: 642 blind_sigᵢ = RSA-FDH-Sign(planchetᵢ, denomᵢ.priv) 643 Persist withdrawal // todo: what exactly? should be checked first for replay? 644 ]]></artwork> 645 <artwork><![CDATA[ 646 (W3) coin unblinding (wallet) 647 648 for i in 0..n: 649 coinᵢ.sig = RSA-FDH-Unblind(blind_sigᵢ, blind_secretᵢ, denomᵢ.pub) 650 Check RSA-FDH-Verify(SHA-512(coinᵢ.pub), coinᵢ.sig, denomᵢ.pub) 651 coinᵢ.h_denom = h_denomᵢ 652 coinᵢ.blind_secret = blind_secretᵢ // todo: why save blind_secret, if batch_seed already persisted? 653 Persist ⟨coinᵢ⟩ 654 ]]></artwork> 655 </section> 656 <section anchor="withdraw-recoup"> 657 <name>Recoup</name> 658 <t>// todo</t> 659 </section> 660 </section> 661 <section anchor="payment-with-e-cash"> 662 <name>Payment with E-Cash</name> 663 <section anchor="payment"> 664 <name>Payment and Deposit</name> 665 <t>The wallet obtains <tt>contract</tt> information for an <tt>order</tt> from the merchant 666 after claiming it with a <tt>nonce</tt>. 667 Payment of the order is prepared by signing (partial) deposit authorizations <tt>⟨depositᵢ⟩</tt> with coins <tt>⟨coinᵢ⟩</tt> of certain denominations <tt>⟨denomᵢ⟩</tt>, 668 where the sum of all contributions (<tt>contributionᵢ <= denomᵢ.value</tt>) must match the <tt>contract.price</tt> plus potential deposit fees. 669 The payment is complete as soon as the merchant successfully redeems the deposit authorizations at the exchange.</t> 670 <t>Deposit could also be used directly by a wallet with its own payto and a minimal contract.</t> 671 <artwork><![CDATA[ 672 wallet merchant exchange 673 Knows ⟨coinᵢ⟩ Knows merchant.priv Knows exchange.priv 674 | Knows exchange, payto Knows ⟨denomᵢ⟩ 675 | | | 676 | +-----------------------+ | 677 | | (M1) order generation | | 678 | +-----------------------+ | 679 | | | 680 |<--- (QR-Code / NFC / URI) ---| | 681 | (order.{id,token?}) | | 682 | | | 683 +-----------------------+ | | 684 | (W1) nonce generation | | | 685 +-----------------------+ | | 686 | | | 687 |-- /orders/{order.id}/claim ->| | 688 | (nonce.pub, order.token?) | | 689 | | | 690 | +--------------------------+ | 691 | | (M2) contract generation | | 692 | +--------------------------+ | 693 | | | 694 |<-- (contract, merchant.pub, -| | 695 | sig) | | 696 | | | 697 +--------------------------+ | | 698 | (W2) payment preparation | | | 699 +--------------------------+ | | 700 | | | 701 |--- /orders/{order.id}/pay -->| | 702 | (⟨depositᵢ⟩) | | 703 | | | 704 | +--------------------------+ | 705 | | (M3) deposit preparation | | 706 | +--------------------------+ | 707 | | | 708 | |-------- /batch-deposit ----->| 709 | | (info, h_contract, ⟨depositᵢ⟩| 710 | | merchant.pub, sig) | 711 | | | 712 | | +--------------------+ 713 | | | (E1) deposit check | 714 | | +--------------------+ 715 | | | 716 | |<- (timestamp, exchange.pub, -| 717 | | sig) | 718 | | | 719 | +---------------------------+ | 720 | | (M4) deposit verification | | 721 | +---------------------------+ | 722 | | | 723 |<----------- (sig) -----------| | 724 | | | 725 +---------------------------+ | | 726 | (W3) payment verification | | | 727 +---------------------------+ | | 728 | | | 729 ]]></artwork> 730 <t>where (without age restriction, policy and wallet data hash)</t> 731 <artwork><![CDATA[ 732 (M1) order generation (merchant) 733 734 wire_salt = random(128) 735 determine id, price, info, token? 736 Persist order = (id, price, info, token?, wire_salt) 737 ]]></artwork> 738 <artwork><![CDATA[ 739 (W1) nonce generation (wallet) 740 741 nonce = Ed25519-Keygen() 742 Persist nonce.priv 743 ]]></artwork> 744 <t>Note that the private key of <tt>nonce</tt> is currently not used anywhere in the protocol. 745 However, it could be used in the future to prove ownership of an order transaction, 746 enabling use-cases such as "unclaiming" or transferring an order to another person, 747 or proving the payment without resorting to the individual coins.</t> 748 <artwork><![CDATA[ 749 (M2) contract generation (merchant) 750 751 Check order.token? == token? 752 h_wire = HKDF(wire_salt, payto, "merchant-wire-signature", 64) 753 determine timestamp, refund_deadline, wire_deadline 754 contract = (order.{id,price,info,token?}, exchange, h_wire, timestamp, refund_deadline, wire_deadline) 755 contract.nonce = nonce.pub 756 Persist contract 757 h_contract = SHA-512(canonicalJSON(contract)) 758 msg = Gen-Msg(MERCHANT_CONTRACT, h_contract) 759 sig = Ed25519-Sign(merchant.priv, msg) 760 ]]></artwork> 761 <artwork><![CDATA[ 762 (W2) payment preparation (wallet) 763 764 h_contract = SHA-512(canonicalJSON(contract)) 765 msg = Gen-Msg(MERCHANT_CONTRACT, h_contract) 766 Check Ed25519-Verify(merchant.pub, msg, sig) 767 Check contract.nonce == nonce 768 // TODO: double-check extra hash check? 769 // todo: maybe get rid of CoinSelection altogether by claiming we already know coinᵢ and contributionᵢ 770 ⟨selectionᵢ⟩ = CoinSelection(contract.{exchange,price}) TODO: include MarkDirty here 771 for i in 0..n: 772 (coinᵢ, denomᵢ, contributionᵢ) = selectionᵢ 773 msgᵢ = Gen-Msg(WALLET_COIN_DEPOSIT, 774 ( h_contract | uint256(0x0) 775 | uint512(0x0) | contract.h_wire | coinᵢ.h_denom 776 | contract.timestamp | contract.refund_deadline 777 | contributionᵢ + denomᵢ.fee_deposit 778 | denomᵢ.fee_deposit | merchant.pub | uint512(0x0) )) 779 sigᵢ = Ed25519-Sign(coinᵢ.priv, msgᵢ) 780 depositᵢ = (coinᵢ.{pub,sig,h_denom}, contributionᵢ, sigᵢ) 781 Persist (contract, ⟨sigᵢ⟩, ⟨depositᵢ⟩) 782 ]]></artwork> 783 <t>// TODO: explain CoinSelection</t> 784 <artwork><![CDATA[ 785 (M3) deposit preparation (merchant) 786 787 Check Sum ⟨depositᵢ.contribution⟩ == contract.price 788 info.time = contract.{timestamp, wire_deadline, refund_deadline} 789 info.wire = (payto, wire_salt) 790 h_contract = SHA-512(canonicalJSON(contract)) 791 msg = Gen-Msg(MERCHANT_CONTRACT, h_contract) 792 sig = Ed25519-Sign(merchant.priv, msg) 793 ]]></artwork> 794 <artwork><![CDATA[ 795 (E1) deposit check (exchange) 796 797 h_wire = HKDF(info.wire.wire_salt, info.wire.payto, "merchant-wire-signature", 64) 798 for i in 0..n: 799 coinᵢ = depositᵢ.coin 800 denomᵢ = Lookup by coinᵢ.h_denom 801 Check denomᵢ known and not deposit-expired 802 totalᵢ = depositᵢ.contribution + denomᵢ.fee_deposit 803 msgᵢ = Gen-Msg(WALLET_COIN_DEPOSIT, 804 ( h_contract | uint256(0x0) 805 | uint512(0x0) | h_wire | coinᵢ.h_denom 806 | info.time.timestamp | info.time.refund_deadline 807 | totalᵢ 808 | denomᵢ.fee_deposit | merchant.pub | uint512(0x0) )) 809 Check Ed25519-Verify(coinᵢ.pub, msgᵢ, depositᵢ.sig) 810 Check RSA-FDH-Verify(SHA-512(coinᵢ.pub), coinᵢ.sig, denomᵢ.pub) 811 Check-Subtract(coinᵢ.value, total) 812 Persist deposit-record 813 schedule bank transfer to payto 814 timestamp = now() 815 msg = Gen-Msg(EXCHANGE_CONFIRM_DEPOSIT, 816 ( h_contract | h_wire | uint512(0x0) 817 | timestamp | info.time.wire_deadline 818 | info.time.refund_deadline 819 | Sum ⟨depositᵢ.contribution⟩ 820 | SHA-512( ⟨depositᵢ.sig⟩ ) | merchant.pub )) 821 sig = Ed25519-Sign(exchange.priv, msg) 822 ]]></artwork> 823 <artwork><![CDATA[ 824 (M2) deposit verification (merchant) 825 826 h_wire = HKDF(wire_salt, payto, "merchant-wire-signature", 64) 827 msg = Gen-Msg(EXCHANGE_CONFIRM_DEPOSIT, 828 ( h_contract | h_wire | uint512(0x0) 829 | timestamp | contract.wire_deadline 830 | contract.refund_deadline 831 | Sum ⟨depositᵢ.contribution⟩ 832 | SHA-512( ⟨depositᵢ.sig⟩ ) | merchant.pub )) 833 Check Ed25519-Verify(exchange.pub, msg, sig) 834 msg = Gen-Msg(MERCHANT_PAYMENT_OK, h_contract) 835 sig = Ed25519-Sign(merchant.priv, msg) 836 ]]></artwork> 837 <artwork><![CDATA[ 838 (W3) payment verification (wallet) 839 840 msg = Gen-Msg(MERCHANT_PAYMENT_OK, h_contract) 841 Check Ed25519-Verify(merchant.pub, msg, sig) 842 ]]></artwork> 843 </section> 844 <section anchor="refund"> 845 <name>Refund</name> 846 <t>A wallet can request a refund for an order from the merchant after it has been completed successfully 847 (cf. <xref target="payment"/>) and before the merchant has been paid out by the exchange (i.e., before <tt>contract.wire_deadline</tt>). 848 The merchant needs to approve the refund via its business logic, 849 and is free to decide the total amount of the refund 850 as well as which coins' deposit operations are (potentially partly) invalidated. 851 After the exchange has accepted the refund request, 852 the coins obtain their (partial) value back. 853 The wallet should proceed to refresh (cf. <xref target="refresh"/>) the coins before spending them again 854 to obtain unlinkability.</t> 855 <t>In case the wallet itself has used deposit to its own payto, 856 it can act as the merchant in the protocol below.</t> 857 <t>// todo: if proves practical, similar strucuture could be used for pay/deposit 858 (interaction) between wallet, merchant and exchange</t> 859 <artwork><![CDATA[ 860 wallet merchant exchange 861 Knows order.id Knows merchant.priv Knows deposit_record 862 Knows contract | for coinᵢ.pub 863 | | | 864 +---------------------+ | | 865 | (W1) refund request | | | 866 +---------------------+ | | 867 | | | 868 |- /orders/{order.id}/refund ->| | 869 | (h_contract) | | 870 | | | 871 | +------------------------+ | 872 | | (M1) refund processing | | 873 | +------------------------+ | 874 | | | 875 | |- /coins/{coinᵢ.pub}/refund ->| 876 | | (valueᵢ, h_contract, id, | 877 | | merchant.pub, sigᵢ) | 878 | | | 879 | | +-------------------+ 880 | | | (E1) refund check | 881 | | +-------------------+ 882 | | | 883 | |<--- (exchange.pub, sigᵢ) ----| 884 | | | 885 | +--------------------------+ | 886 | | (M2) refund confirmation | | 887 | +--------------------------+ | 888 | | | 889 |<-----(value, ⟨refundᵢ⟩,------| | 890 | merchant.pub) | | // todo: why merchant.pub if no sig transmitted? 891 | | | 892 +-----------------------+ | | 893 | (W2) refund reception | | | 894 +-----------------------+ | | 895 | | | 896 ]]></artwork> 897 <t>where (for RSA, without age-restriction)</t> 898 <artwork><![CDATA[ 899 (W1) refund request (wallet) 900 901 h_contract = SHA-512(canonicalJSON(contract)) 902 ]]></artwork> 903 <artwork><![CDATA[ 904 (M1) refund processing (merchant) 905 906 Check h_contract known and refund possible 907 time = now() 908 ⟨coinᵢ⟩ = Lookup by h_contract 909 id = ? 910 for i in 0..n: 911 denomᵢ = Lookup by coinᵢ.h_denom 912 valueᵢ = refund amount // todo: split wisely 913 msgᵢ = Gen-Msg(MERCHANT_REFUND, 914 ( h_contract | coinᵢ.pub | id | valueᵢ | denomᵢ.fee_refund )) 915 sigᵢ = Ed25519-Sign(merchant.priv, msgᵢ) 916 ]]></artwork> 917 <artwork><![CDATA[ 918 (E1) refund check and confirmation (exchange) 919 920 deposit_record = Lookup by h_contract // todo: needs to be persisted before with order.id and used coins! 921 Check coinᵢ.pub part of deposit_record 922 denomᵢ = Lookup by coinᵢ.pub 923 msgᵢ = Gen-Msg(MERCHANT_REFUND, 924 ( h_contract | coinᵢ.pub | id | valueᵢ | denomᵢ.fee_refund )) 925 Check Ed25519-Verify(merchant.pub, msgᵢ, sigᵢ) 926 Check valueᵢ >= denomᵢ.fee_refund 927 Check refund possible (prior to wire transfer deadline) 928 remove/update scheduled wire transfer 929 mark coin part as unspent 930 msgᵢ = Gen-Msg(MERCHANT_REFUND_OK, SHA-512(order.id)) // todo: hashing string without terminating \0 931 sigᵢ = Ed25519-Sign(exchange.priv, msgᵢ) 932 ]]></artwork> 933 <artwork><![CDATA[ 934 (M2) refund confirmation (merchant) 935 936 for i in 0..n: 937 msgᵢ = Gen-Msg(MERCHANT_REFUND_OK, SHA-512(order.id)) // todo: hashing string without terminating \0 938 Check Ed25519-Verify(exchange.pub, msgᵢ, sigᵢ) 939 update business logic 940 refundᵢ = (valueᵢ, sigᵢ, id, coinᵢ.pub, time) 941 value = sum ⟨valueᵢ⟩ 942 ]]></artwork> 943 <artwork><![CDATA[ 944 (W2) refund reception (wallet) 945 946 for i in 0..n: 947 (valueᵢ, sigᵢ, id, coinᵢ.pub, time) = refundᵢ 948 update persistent transaction information 949 refresh ⟨coinᵢ⟩ 950 ]]></artwork> 951 </section> 952 </section> 953 <section anchor="obtaining-unlinkable-change"> 954 <name>Obtaining unlinkable change</name> 955 <section anchor="refresh"> 956 <name>Refresh</name> 957 <t>The wallet obtains <tt>n</tt> new coins <tt>⟨coinᵢ⟩</tt> of denominations <tt>⟨denomᵢ⟩</tt> 958 in exchange for one old <tt>coin</tt> of denomination <tt>denom</tt> from the exchange. 959 There are three reasons why a wallet needs to do this:</t> 960 <ol spacing="normal" type="1"><li> 961 <t>Obtaining unlinkable change after using only a part of the coin's value during a payment (cf. <xref target="payment"/>), 962 i.e. where <tt>contribution <= denom.value</tt></t> 963 </li> 964 <li> 965 <t>Obtaining unlinkable change after a successful refund (cf. <xref target="refund"/>)</t> 966 </li> 967 <li> 968 <t>Renewing a coin before it deposit-expires</t> 969 </li> 970 </ol> 971 <t>The sum of the refresh fee of <tt>denom</tt> and the new denominations' values and withdrawal fees (defined by the exchange) 972 must be smaller or equal to the residual value of the old <tt>coin</tt>.</t> 973 <t>The private key of each new coin candidate <tt>⟨coinₖᵢ.priv⟩</tt> is transitively derived from the old coin's private key <tt>coin.priv</tt> 974 via a 512-bit secret <tt>⟨sharedₖᵢ⟩</tt> according to <tt>Refresh-Derive</tt>. 975 The secret is regeneratable with the knowledge of <tt>coin.priv</tt> via the link protocol (cf. <xref target="link"/>). 976 The derivation ensures that ownership of coins (knowledge of the private key) is correctly transferred, 977 and thereby that value transfer among untrusted parties can only happen via payment and deposit, not via refresh.</t> 978 <artwork><![CDATA[ 979 Refresh-Derive(shared, denom) = 980 planchet_seed = HKDF(uint32(i), shared, "taler-coin-derivation", 64) 981 blind_secret = HKDF("bks", planchet_seed, "", 32) 982 coin.priv = HKDF("coin", planchet_seed, "", 32) 983 coin.pub = Ed25519-GetPub(coin.priv) 984 planchet = RSA-FDH-Blind(SHA-512(coin.pub), blind_secret, denomᵢ.pub) 985 h_planchet = Hash-Planchet(planchet, denomᵢ) 986 return (coin, blind_secret, planchet, h_planchet) 987 ]]></artwork> 988 <t>Taler uses a cut-and-choose protocol with the fixed parameter <tt>κ=3</tt> to enforce correct derivation 989 of <tt>⟨sharedₖᵢ⟩</tt> from a single seed per batch of planchets <tt>⟨batch_seedₖ⟩</tt> 990 (in (κ-1)/κ of the cases, making income concealment for tax evasion purposes unpractical).</t> 991 <t>Refreshing consists of two parts:</t> 992 <ol spacing="normal" type="1"><li> 993 <t>Melting of the old coin and commiting to κ batches of blinded planchet candidates</t> 994 </li> 995 <li> 996 <t>Revelation of κ-1 secrets <tt>⟨revealed_seedₖ⟩</tt> to prove the proper construction of the (revealed) batches of blinded planchet candidates.</t> 997 </li> 998 </ol> 999 <artwork><![CDATA[ 1000 wallet exchange 1001 Knows ⟨denomᵢ⟩ Knows ⟨denomᵢ.priv⟩ 1002 Knows coin | 1003 | | 1004 +-------------------+ | 1005 | (W1) coin melting | | 1006 +-------------------+ | 1007 | | 1008 |---------------- /melt ---------------->| 1009 | (coin.{pub,sig,h_denom}, value, | 1010 | refresh_seed, planchets, sig) | 1011 | | 1012 | +---------------------------------------+ 1013 | | (E1) gamma selection and coin signing | 1014 | +---------------------------------------+ 1015 | | 1016 |<------ (ɣ, exchange.pub, sig) ---------| 1017 | | 1018 +------------------------+ | 1019 | (W2) secret revelation | | 1020 +------------------------+ | 1021 | | 1022 |------------ /reveal-melt ------------->| 1023 | (commitment, ⟨revealed_seedₖ⟩) | 1024 | | 1025 | +----------------------------+ 1026 | | (E2) commitment validation | 1027 | +----------------------------+ 1028 | | 1029 |<---------- (⟨blind_sigᵢ⟩) -------------| 1030 | | 1031 +----------------------+ | 1032 | (W3) coin unblinding | | 1033 +----------------------+ | 1034 | | 1035 ]]></artwork> 1036 <t>where (for RSA, without age-restriction)</t> 1037 <artwork><![CDATA[ 1038 (W1) coin melting (wallet) 1039 1040 refresh_seed = random(256) 1041 ⟨batch_seedₖ⟩ = HKDF("refresh-batch-seeds", refresh_seed, coin.priv, k*64) 1042 for k in 0..κ: 1043 ⟨transferₖᵢ.priv⟩ = HKDF("refresh-transfer-private-keys", batch_seedₖ, "", n*32) 1044 for i in 0..n: 1045 transferₖᵢ.pub = ECDH-GetPub(transferₖᵢ.priv) 1046 sharedₖᵢ = ECDH-Ed25519-Pub(transferₖᵢ.priv, coin.pub) 1047 (coinₖᵢ, blind_secretₖᵢ, planchetₖᵢ, h_planchetₖᵢ) = Refresh-Derive(sharedₖᵢ, denomᵢ) 1048 h_planchetsₖ = SHA-512( ⟨h_planchetₖᵢ⟩ ) 1049 value = coin.denom.fee_refresh + Sum ⟨denomᵢ.value⟩ + Sum ⟨denomᵢ.fee_withdraw⟩ 1050 commitment = SHA-512( refresh_seed | uint256(0x0) | coin.pub | value 1051 | SHA-512( ⟨h_planchetsₖ⟩ ) ) 1052 for i in 0..n: 1053 h_denomᵢ = Hash-Denom(denomᵢ) 1054 planchets = (⟨h_denomᵢ⟩, ⟨planchetₖᵢ⟩, ⟨transferₖᵢ.pub⟩)) 1055 msg = Gen-Msg(WALLET_COIN_MELT, 1056 ( commitment | coin.h_denom | uint256(0x0) 1057 | value | denom.fee_refresh )) 1058 sig = Ed25519-Sign(coin.priv, msg) 1059 Persist (coin.denom.pub, ...) // todo: double-check 1060 ]]></artwork> 1061 <artwork><![CDATA[ 1062 (E1) gamma selection and coin signing (exchange) 1063 1064 denom = Lookup by coin.h_denom 1065 Check denom known and not deposit-expired 1066 Check RSA-FDH-Verify(SHA-512(coin.pub), coin.sig, denom.pub) 1067 Check coin.pub known and dirty 1068 (⟨h_denomᵢ⟩, ⟨planchetₖᵢ⟩, ⟨transferₖᵢ.pub⟩)) = planchets 1069 for i in 0..n: 1070 denomᵢ = Lookup by h_denomᵢ 1071 Check denomᵢ known and not withdraw-expired 1072 value' = coin.denom.fee_refresh + Sum ⟨denomᵢ.value⟩ + Sum ⟨denomᵢ.fee_withdraw⟩ 1073 Check value' == value 1074 Check-Subtract(coin.value, value) 1075 for k in 0..κ: 1076 for i in 0..n: 1077 h_planchetₖᵢ = Hash-Planchet(planchetₖᵢ, denomᵢ) 1078 h_planchetsₖ = SHA-512( ⟨h_planchetₖᵢ⟩ ) 1079 commitment = SHA-512( refresh_seed | uint256(0x0) | coin.pub | value 1080 | SHA-512( ⟨h_planchetsₖ⟩ ) ) 1081 msg = Gen-Msg(WALLET_COIN_MELT, 1082 ( commitment | coin.h_denom | uint256(0x0) 1083 | value | denom.fee_refresh )) 1084 Check Ed25519-Verify(coin.pub, msg, sig) 1085 refresh_record = Lookup by commitment 1086 (ɣ, _, _, done, _) = refresh_record 1087 if refresh_record not found: 1088 ɣ = 0..κ at random 1089 for i in 0..n: 1090 blind_sigᵢ = RSA-FDH-Sign(planchetᵧᵢ, denomᵧᵢ.priv) 1091 link_info = (refresh_seed, ⟨transferₖᵢ.pub⟩, ⟨h_denomᵢ⟩, coin_sig) 1092 Persist refresh_record = (commitment, ɣ, ⟨blind_sigᵢ⟩, h_planchetsᵧ, false, link_info) 1093 msg = Gen-Msg(EXCHANGE_CONFIRM_MELT, 1094 ( commitment | uint32(ɣ) )) 1095 sig = Ed25519-Sign(exchange.priv, msg) 1096 ]]></artwork> 1097 <artwork><![CDATA[ 1098 (W2) secret revelation (wallet) 1099 1100 Check exchange.pub known 1101 msg = Gen-Msg(EXCHANGE_CONFIRM_MELT, 1102 ( commitment | ɣ )) 1103 Check Ed25519-Verify(exchange.pub, msg, sig) 1104 Persist refresh-challenge // what exactly? 1105 for k in 0..κ and k != ɣ: 1106 revealed_seedₖ = batch_seedₖ 1107 ]]></artwork> 1108 <artwork><![CDATA[ 1109 (E2) commitment validation (exchange) 1110 1111 refresh_record = Lookup by commitment 1112 (ɣ, ⟨blind_sigᵢ⟩, h_planchetsᵧ, done, _) = refresh_record 1113 Check not done // todo: sure? 1114 for k in 0..κ and k != ɣ: 1115 ⟨transferₖᵢ.priv⟩ = HKDF("refresh-transfer-private-keys", batch_seedₖ, "", n*32) 1116 for i in 0..n: 1117 transferₖᵢ.pub = ECDH-GetPub(transferₖᵢ.priv) 1118 sharedₖᵢ = ECDH-Ed25519-Pub(transferₖᵢ.priv, coin.pub) 1119 (_, _, _, h_planchetₖᵢ) = Refresh-Derive(sharedₖᵢ, denomᵢ) 1120 h_planchetsₖ = SHA-512( ⟨h_planchetₖᵢ⟩ ) 1121 value = coin.denom.fee_refresh + Sum ⟨denomᵢ.value⟩ + Sum ⟨denomᵢ.fee_withdraw⟩ 1122 commitment' = SHA-512( refresh_seed | uint256(0x0) | coin.pub | value 1123 | SHA-512( ⟨h_planchetsₖ⟩ ) ) 1124 Check commitment == commitment' 1125 Persist refresh_record = (_, _, _, true, _) 1126 ]]></artwork> 1127 <artwork><![CDATA[ 1128 (W3) coin unblinding (wallet) 1129 1130 for i in 0..n: 1131 coinᵧᵢ.sig = RSA-FDH-Unblind(blind_sigᵧᵢ, blind_secretᵧᵢ, denomᵢ.pub) 1132 Check RSA-FDH-Verify(SHA-512(coinᵧᵢ.pub), coinᵧᵢ.sig, denomᵢ.pub) 1133 coinᵧᵢ.h_denom = h_denomᵢ 1134 Persist ⟨coinᵧᵢ⟩ 1135 ]]></artwork> 1136 </section> 1137 <section anchor="link"> 1138 <name>Link</name> 1139 <t>Coins ⟨coinᵧᵢ⟩ obtained via the refresh protocol (cf. <xref target="refresh"/>) can be regenerated 1140 with the knowledge of the old coin's private key <tt>coin.priv</tt> using the link protocol, 1141 integrated in the coin history endpoint.</t> 1142 <artwork><![CDATA[ 1143 wallet exchange 1144 Knows coin Knows refresh_record for coin.pub 1145 | | 1146 +----------------------+ | 1147 | (W1) history request | | 1148 +----------------------+ | 1149 | | 1150 |------ /coins/{coin.pub}/history ------>| 1151 | (sig) | 1152 | | 1153 | +----------------------------+ 1154 | | (E1) refresh secret lookup | 1155 | +----------------------------+ 1156 | | 1157 |<------------- (melt_info) -------------| 1158 | | 1159 +-----------------------+ | 1160 | (W2) coin acquisition | | 1161 +-----------------------+ | 1162 | | 1163 ]]></artwork> 1164 <t>where (for RSA, without age-restriction)</t> 1165 <artwork><![CDATA[ 1166 (W1) history request (wallet) 1167 1168 msg = Gen-Msg(COIN_HISTORY_REQUEST, uint64(0x0)) 1169 sig = Ed25519-Sign(coin.priv, msg) 1170 ]]></artwork> 1171 <artwork><![CDATA[ 1172 (E1) refresh secret lookup (exchange) 1173 1174 refresh_record = Lookup by coin.pub 1175 (ɣ, ⟨blind_sigᵢ⟩, _, done, link_info) = refresh_record 1176 if done: 1177 melt_info = (ɣ, link_info, ⟨blind_sigᵢ⟩) 1178 else: 1179 melt_info = (ɣ, link_info) 1180 ]]></artwork> 1181 <artwork><![CDATA[ 1182 (W2) coin acquisition (wallet) 1183 1184 (ɣ, link_info, ⟨blind_sigᵢ⟩?) = melt_info 1185 (refresh_seed, ⟨transferₖᵢ.pub⟩, ⟨h_denomᵢ⟩, coin_sig) = link_info 1186 1187 for i in 0..n: 1188 denomᵢ = Lookup by h_denomᵢ 1189 for k in 0..κ: 1190 for i in 0..n: 1191 sharedₖᵢ = ECDH-Ed25519-Priv(coin.priv, transferₖᵢ.pub) 1192 (coinₖᵢ, blind_secretₖᵢ _, h_planchetₖᵢ) = Refresh-Derive(sharedₖᵢ, denomᵢ) 1193 h_planchetsₖ = SHA-512( ⟨h_planchetₖᵢ⟩ ) 1194 value = coin.denom.fee_refresh + Sum ⟨denomᵢ.value⟩ + Sum ⟨denomᵢ.fee_withdraw⟩ 1195 commitment = SHA-512( refresh_seed | uint256(0x0) | coin.pub | value 1196 | SHA-512( ⟨h_planchetsₖ⟩ ) ) 1197 msg = Gen-Msg(WALLET_COIN_MELT, 1198 ( commitment | coin.h_denom | uint256(0x0) 1199 | value | denom.fee_refresh )) 1200 Check Ed25519-Verify(coin.pub, msg, sig) 1201 1202 if ⟨blind_sigᵢ⟩ returned: 1203 for i in 0..n: 1204 coinᵧᵢ.sig = RSA-FDH-Unblind(blind_sigᵧᵢ, blind_secretᵧᵢ, denomᵢ.pub) 1205 Check RSA-FDH-Verify(SHA-512(coinᵧᵢ.pub), coinᵧᵢ.sig, denomᵢ.pub) 1206 coinᵧᵢ.h_denom = h_denomᵢ 1207 Persist ⟨coinᵧᵢ⟩ 1208 ]]></artwork> 1209 </section> 1210 <section anchor="refresh-recoup"> 1211 <name>Recoup</name> 1212 <t>// todo</t> 1213 </section> 1214 </section> 1215 <section anchor="w2w"> 1216 <name>Transfer of E-Cash</name> 1217 <t>// todo: introductory text</t> 1218 <t>Transactions in E-Cash between wallets. 1219 Commonly referred to as peer-to-peer transactions. 1220 In Taler, interaction with exchange, therefore called wallet-to-wallet transactions.</t> 1221 <section anchor="w2w-account"> 1222 <name>Account Creation</name> 1223 </section> 1224 <section anchor="w2w-push"> 1225 <name>Push Payment</name> 1226 <t>// todo</t> 1227 </section> 1228 <section anchor="w2w-pull"> 1229 <name>Pull Payment</name> 1230 <t>// todo</t> 1231 </section> 1232 </section> 1233 </section> 1234 <section anchor="security-considerations"> 1235 <name>Security Considerations</name> 1236 <t>[ TBD ]</t> 1237 </section> 1238 <section anchor="iana-considerations"> 1239 <name>IANA Considerations</name> 1240 <t>None.</t> 1241 </section> 1242 </middle> 1243 <back> 1244 <references anchor="sec-normative-references"> 1245 <name>Normative References</name> 1246 <reference anchor="RFC20"> 1247 <front> 1248 <title>ASCII format for network interchange</title> 1249 <author fullname="V.G. Cerf" initials="V.G." surname="Cerf"/> 1250 <date month="October" year="1969"/> 1251 </front> 1252 <seriesInfo name="STD" value="80"/> 1253 <seriesInfo name="RFC" value="20"/> 1254 <seriesInfo name="DOI" value="10.17487/RFC0020"/> 1255 </reference> 1256 <reference anchor="RFC2104"> 1257 <front> 1258 <title>HMAC: Keyed-Hashing for Message Authentication</title> 1259 <author fullname="H. Krawczyk" initials="H." surname="Krawczyk"/> 1260 <author fullname="M. Bellare" initials="M." surname="Bellare"/> 1261 <author fullname="R. Canetti" initials="R." surname="Canetti"/> 1262 <date month="February" year="1997"/> 1263 <abstract> 1264 <t>This document describes HMAC, a mechanism for message authentication using cryptographic hash functions. HMAC can be used with any iterative cryptographic hash function, e.g., MD5, SHA-1, in combination with a secret shared key. The cryptographic strength of HMAC depends on the properties of the underlying hash function. This memo provides information for the Internet community. This memo does not specify an Internet standard of any kind</t> 1265 </abstract> 1266 </front> 1267 <seriesInfo name="RFC" value="2104"/> 1268 <seriesInfo name="DOI" value="10.17487/RFC2104"/> 1269 </reference> 1270 <reference anchor="RFC5869"> 1271 <front> 1272 <title>HMAC-based Extract-and-Expand Key Derivation Function (HKDF)</title> 1273 <author fullname="H. Krawczyk" initials="H." surname="Krawczyk"/> 1274 <author fullname="P. Eronen" initials="P." surname="Eronen"/> 1275 <date month="May" year="2010"/> 1276 <abstract> 1277 <t>This document specifies a simple Hashed Message Authentication Code (HMAC)-based key derivation function (HKDF), which can be used as a building block in various protocols and applications. The key derivation function (KDF) is intended to support a wide range of applications and requirements, and is conservative in its use of cryptographic hash functions. This document is not an Internet Standards Track specification; it is published for informational purposes.</t> 1278 </abstract> 1279 </front> 1280 <seriesInfo name="RFC" value="5869"/> 1281 <seriesInfo name="DOI" value="10.17487/RFC5869"/> 1282 </reference> 1283 <reference anchor="RFC6234"> 1284 <front> 1285 <title>US Secure Hash Algorithms (SHA and SHA-based HMAC and HKDF)</title> 1286 <author fullname="D. Eastlake 3rd" initials="D." surname="Eastlake 3rd"/> 1287 <author fullname="T. Hansen" initials="T." surname="Hansen"/> 1288 <date month="May" year="2011"/> 1289 <abstract> 1290 <t>Federal Information Processing Standard, FIPS</t> 1291 </abstract> 1292 </front> 1293 <seriesInfo name="RFC" value="6234"/> 1294 <seriesInfo name="DOI" value="10.17487/RFC6234"/> 1295 </reference> 1296 <reference anchor="RFC7748"> 1297 <front> 1298 <title>Elliptic Curves for Security</title> 1299 <author fullname="A. Langley" initials="A." surname="Langley"/> 1300 <author fullname="M. Hamburg" initials="M." surname="Hamburg"/> 1301 <author fullname="S. Turner" initials="S." surname="Turner"/> 1302 <date month="January" year="2016"/> 1303 <abstract> 1304 <t>This memo specifies two elliptic curves over prime fields that offer a high level of practical security in cryptographic applications, including Transport Layer Security (TLS). These curves are intended to operate at the ~128-bit and ~224-bit security level, respectively, and are generated deterministically based on a list of required properties.</t> 1305 </abstract> 1306 </front> 1307 <seriesInfo name="RFC" value="7748"/> 1308 <seriesInfo name="DOI" value="10.17487/RFC7748"/> 1309 </reference> 1310 <reference anchor="RFC8032"> 1311 <front> 1312 <title>Edwards-Curve Digital Signature Algorithm (EdDSA)</title> 1313 <author fullname="S. Josefsson" initials="S." surname="Josefsson"/> 1314 <author fullname="I. Liusvaara" initials="I." surname="Liusvaara"/> 1315 <date month="January" year="2017"/> 1316 <abstract> 1317 <t>This document describes elliptic curve signature scheme Edwards-curve Digital Signature Algorithm (EdDSA). The algorithm is instantiated with recommended parameters for the edwards25519 and edwards448 curves. An example implementation and test vectors are provided.</t> 1318 </abstract> 1319 </front> 1320 <seriesInfo name="RFC" value="8032"/> 1321 <seriesInfo name="DOI" value="10.17487/RFC8032"/> 1322 </reference> 1323 <reference anchor="HKDF"> 1324 <front> 1325 <title>Cryptographic Extraction and Key Derivation: The HKDF Scheme</title> 1326 <author fullname="Hugo Krawczyk" initials="H." surname="Krawczyk"> 1327 <organization/> 1328 </author> 1329 <date year="2010"/> 1330 </front> 1331 <seriesInfo name="Lecture Notes in Computer Science" value="pp. 631-648"/> 1332 <seriesInfo name="DOI" value="10.1007/978-3-642-14623-7_34"/> 1333 <seriesInfo name="ISBN" value="["9783642146220", "9783642146237"]"/> 1334 <refcontent>Springer Berlin Heidelberg</refcontent> 1335 </reference> 1336 <reference anchor="SHS"> 1337 <front> 1338 <title>Secure hash standard</title> 1339 <author> 1340 <organization/> 1341 </author> 1342 <date year="2015"/> 1343 </front> 1344 <seriesInfo name="DOI" value="10.6028/nist.fips.180-4"/> 1345 <refcontent>National Institute of Standards and Technology (U.S.)</refcontent> 1346 </reference> 1347 </references> 1348 <?line 1386?> 1349 1350 <section anchor="test-vectors"> 1351 <name>Test Vectors</name> 1352 <t>This appendix provides two sets of test vectors for testing Taler Protocol implementations. 1353 They are generated by going through the protocol operations in the following order:</t> 1354 <ol spacing="normal" type="1"><li> 1355 <t>Withdraw two coins <tt>coin₀</tt> and <tt>coin₁</tt> from a single <tt>reserve</tt> (cf. <xref target="withdraw"/>).</t> 1356 </li> 1357 <li> 1358 <t>Pay for one <tt>order</tt> with the full value of <tt>coin₀</tt> and a partial value of <tt>coin₁</tt> (cf. <xref target="payment"/>).</t> 1359 </li> 1360 <li> 1361 <t>Obtain a partial refund for <tt>coin₀</tt> used to pay for the <tt>order</tt> (cf. <xref target="refund"/>).</t> 1362 </li> 1363 <li> 1364 <t>Refresh the now-dirty <tt>coin₁</tt> to two new coins <tt>coin₂</tt> and <tt>coin₃</tt> (cf. <xref target="refresh"/>).</t> 1365 </li> 1366 <li> 1367 <t>Regenerate <tt>coin₂</tt> and <tt>coin₃</tt> with the knowledge of <tt>coin₁</tt> (cf. <xref target="link"/>).</t> 1368 </li> 1369 <li> 1370 <t>Create an <tt>account</tt> for w2w transfers (cf. <xref target="w2w-account"/>).</t> 1371 </li> 1372 <li> 1373 <t>Send a payment to <tt>account</tt> with the full value of <tt>coin₂</tt>, obtaining <tt>coin₅</tt> (cf. <xref target="w2w-push"/>).</t> 1374 </li> 1375 <li> 1376 <t>Request a payment to <tt>account</tt>, which is paid with the full value of <tt>coin₅</tt>, obtaining <tt>coin₆</tt> (cf. <xref target="w2w-pull"/>).</t> 1377 </li> 1378 <li> 1379 <t>Recoup the value of <tt>coin₆</tt> obtained via withdrawal from <tt>account</tt> (cf. <xref target="withdraw-recoup"/>).</t> 1380 </li> 1381 <li> 1382 <t>Recoup the value of <tt>coin₃</tt> obtained via refresh from <tt>coin₁</tt> (cf. <xref target="refresh-recoup"/>).</t> 1383 </li> 1384 </ol> 1385 <t>The test vectors in this document have been generated by the GNU Taler reference implementation written in C. 1386 All binary data is provided in hexadecimal notation.</t> 1387 <section anchor="test-case-1"> 1388 <name>Test Case 1</name> 1389 <artwork><![CDATA[ 1390 denom₀.priv = XXX 1391 denom₀.pub = XXX 1392 denom₀.value = XXX 1393 denom₀.fee_withdraw = XXX 1394 denom₁.priv = XXX 1395 denom₁.pub = XXX 1396 denom₁.value = XXX 1397 denom₁.fee_withdraw = XXX 1398 ]]></artwork> 1399 <section anchor="tc1-withdraw"> 1400 <name>Withdrawal</name> 1401 <artwork><![CDATA[ 1402 (W1) reserve key generation (wallet) 1403 1404 reserve.priv = XXX 1405 reserve.pub = XXX 1406 reserve.balance = XXX 1407 ]]></artwork> 1408 <artwork><![CDATA[ 1409 (W2) coin generation and blinding (wallet) 1410 1411 batch_seed = XXX 1412 coin_seed₀ = XXX 1413 coin_seed₁ = XXX 1414 blind_secret₀ = XXX 1415 blind_secret₁ = XXX 1416 coin₀.priv = XXX 1417 coin₁.priv = XXX 1418 coin₀.pub = XXX 1419 coin₁.pub = XXX 1420 h_denom₀ = XXX 1421 h_denom₁ = XXX 1422 planchet₀ = XXX 1423 planchet₁ = XXX 1424 h_planchet₀ = XXX 1425 h_planchet₁ = XXX 1426 msg = XXX 1427 sig = XXX 1428 ]]></artwork> 1429 <artwork><![CDATA[ 1430 (E1) coin issuance and signing (exchange) 1431 1432 total = XXX 1433 blind_sig₀ = XXX 1434 blind_sig₁ = XXX 1435 ]]></artwork> 1436 <artwork><![CDATA[ 1437 (W3) coin unblinding (wallet) 1438 1439 coin₀.sig = XXX 1440 coin₁.sig = XXX 1441 ]]></artwork> 1442 </section> 1443 <section anchor="tc1-payment"> 1444 <name>Payment and Deposit</name> 1445 </section> 1446 <section anchor="tc1-refund"> 1447 <name>Refund</name> 1448 </section> 1449 <section anchor="tc1-refresh"> 1450 <name>Refresh</name> 1451 </section> 1452 <section anchor="tc1-link"> 1453 <name>Link</name> 1454 </section> 1455 <section anchor="tc1-w2w-account"> 1456 <name>Account Creation</name> 1457 </section> 1458 <section anchor="tc1-w2w-push"> 1459 <name>Push Payment</name> 1460 </section> 1461 <section anchor="tc1-w2w-pull"> 1462 <name>Pull Payment</name> 1463 </section> 1464 <section anchor="tc1-withdraw-recoup"> 1465 <name>Recoup Withdrawal</name> 1466 </section> 1467 <section anchor="tc1-refresh-recoup"> 1468 <name>Recoup Refresh</name> 1469 </section> 1470 </section> 1471 <section anchor="test-case-2"> 1472 <name>Test Case 2</name> 1473 </section> 1474 </section> 1475 <section anchor="change-log"> 1476 <name>Change log</name> 1477 </section> 1478 <section numbered="false" anchor="acknowledgments"> 1479 <name>Acknowledgments</name> 1480 <t>[ TBD ]</t> 1481 <t>This work was supported in part by the German Federal Ministry of 1482 Education and Research (BMBF) within the project Concrete Contracts.</t> 1483 </section> 1484 </back> 1485 <!-- ##markdown-source: 1486 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 1600 Keoo85SO1xqnCCbAqC13H9E65ffjEzUR6xcFaOhau0BQL8uVn8HetHQAQx1z 1601 DROlRdvjt73pHEgGhY7yJcAph2XDOApWPr3AS9OsVGFZGqAHVGJsl04f8ocS 1602 jJ61r+au1un+48PjwZP97wYHTx8dnXBiN4JUcshWyGg6OOnShR3OTzJDgZYi 1603 1XLZASfgyCch4HlGABx8dcKnXVg/auvX/mgseSxzXMQv71Zr3UPnBXSp5GDB 1604 gd/w55X3UXfVz0crer4SrW+BueitOXdyd1aA8DZzvvk6qw+sCUVr5CfnIFv9 1605 JD9D5ch690XDnC1gdygzdvXae5SrwfS7q/L3bhba5nar8dj9aMNhXhmG3nIW 1606 pC2/9wtNA3xrCGY52TCR7rSJD9rUSbfOtOetCZC3mfPN11l94M4m+prrCfdF 1607 E5HCj7ubWgXIVULRzUPb3G4tHjcn09bhttrKKM/nmGxCG6mNy/cOUQOMtZ6f 1608 W/vXqovztruVb7MdS5a1nJ2annhI7ijMzpOV5+LG5qw+WNej7EkaJrtHWiiJ 1609 j0/2OySnUR0HUxfseEw3Zu8Uy+hVgqrFQhta6gZlAqPO3vSqDFIzxzJGq0R/ 1610 SK7vXCteNpth536ukkF8znQnZc7Xak4u0f0gbfWm1Fg6XpGOOV2M3S9leAbd 1611 9leor4ENRdfUcfmgTYMZ65/TbEmZFqJuPknQa2PlLiNNC+eO8D41uhHRSwTq 1612 O8WX/WTB9iT5RpXPchqNJ6TOKV1S3bjVk2AOts5Rixe2jqYOACGjj2giJcZu 1613 bV1RRrcTqXKH3x083D/6+nAwS/NioNEzIMO7D+YnGvsDQjpYSekcrWZ2yBGq 1614 eHO6ARp3LTA/RmBWL5ZgBAnLkM060VESz8gvgsmAkOimxGrSKRt4SLURrg1v 1615 yaLfBuegV8AUdGK5MuAiTCA3XTviFlfbKAmki527obnbdKtDVzWEg2ge157m 1616 hzs7uy/U1FqTrDbZvbPjNGlK7rX746yTgVZOcSEVSxieYhstiriRG4jW5qw1 1617 KWLAXYuyhPV7mtYdtNmCdrq2PSMSMYABvLmEHThzBxVtqyMyaw/9c3tC+wC/ 1618 3X/8+PB0cHx4cnj8y8PBt49OH94/3v+2Q8wNLHPl49CgEstABf9V7RWYUoao 1619 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 1754 1755 --> 1756 1757 </rfc>