draft-guetschow-taler-protocol.xml (41978B)
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="02"/> 28 <workgroup>independent</workgroup> 29 <keyword>taler</keyword> 30 <keyword>cryptography</keyword> 31 <keyword>ecash</keyword> 32 <keyword>payments</keyword> 33 <abstract> 34 <?line 43?> 35 36 <t>[ TBW ]</t> 37 </abstract> 38 </front> 39 <middle> 40 <?line 47?> 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> encoded in network byte order (big endian)</t> 68 </li> 69 <li> 70 <t><tt>uint16(x)</tt>/<tt>uint32(x)</tt>/<tt>uint64(x)</tt>/<tt>uint256(x)</tt>/<tt>uint512(x)</tt> is equivalent to <tt>uint(16, x)</tt>/<tt>uint(32, x)</tt>/<tt>uint(64, x)</tt>/<tt>uint(256, x)</tt>/<tt>uint(512, x)</tt>, respectively</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 </ul> 79 </section> 80 <section anchor="cryptographic-primitives"> 81 <name>Cryptographic Primitives</name> 82 <section anchor="cryptographic-hash-functions"> 83 <name>Cryptographic Hash Functions</name> 84 <section anchor="sha256"> 85 <name>SHA-256</name> 86 <artwork><![CDATA[ 87 SHA-256(msg) -> hash 88 89 Input: 90 msg input message of length L < 2^61 octets 91 92 Output: 93 hash message digest of fixed length HashLen = 32 octets 94 ]]></artwork> 95 <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> 96 </section> 97 <section anchor="sha512"> 98 <name>SHA-512</name> 99 <artwork><![CDATA[ 100 SHA-512(msg) -> hash 101 102 Input: 103 msg input message of length L < 2^125 octets 104 105 Output: 106 hash message digest of fixed length HashLen = 64 octets 107 ]]></artwork> 108 <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> 109 </section> 110 <section anchor="sha512-trunc"> 111 <name>SHA-512-256 (truncated SHA-512)</name> 112 <artwork><![CDATA[ 113 SHA-512-256(msg) -> hash 114 115 Input: 116 msg input message of length L < 2^125 octets 117 118 Output: 119 hash message digest of fixed length HashLen = 32 octets 120 ]]></artwork> 121 <t>The output <tt>hash</tt> corresponds to the first 32 octets of the output of SHA-512 defined in <xref target="sha512"/>:</t> 122 <artwork><![CDATA[ 123 temp = SHA-512(msg) 124 hash = temp[0:31] 125 ]]></artwork> 126 <t>Note that this operation differs from SHA-512/256 as defined in <xref target="SHS"/> in the initial hash value.</t> 127 </section> 128 </section> 129 <section anchor="message-authentication-codes"> 130 <name>Message Authentication Codes</name> 131 <section anchor="hmac"> 132 <name>HMAC</name> 133 <artwork><![CDATA[ 134 HMAC-Hash(key, text) -> out 135 136 Option: 137 Hash cryptographic hash function with output length HashLen 138 139 Input: 140 key secret key of length at least HashLen 141 text input data of arbitary length 142 143 Output: 144 out output of length HashLen 145 ]]></artwork> 146 <t><tt>out</tt> is calculated as defined in <xref target="RFC2104"/>.</t> 147 </section> 148 </section> 149 <section anchor="key-derivation-functions"> 150 <name>Key Derivation Functions</name> 151 <section anchor="hkdf"> 152 <name>HKDF</name> 153 <t>The Hashed Key Derivation Function (HKDF) used in Taler is an instantiation of <xref target="RFC5869"/> 154 with two different hash functions for the Extract and Expand step as suggested in <xref target="HKDF"/>: 155 <tt>HKDF-Extract</tt> uses <tt>HMAC-SHA512</tt>, while <tt>HKDF-Expand</tt> uses <tt>HMAC-SHA256</tt> (cf. <xref target="hmac"/>).</t> 156 <artwork><![CDATA[ 157 HKDF(salt, IKM, info, L) -> OKM 158 159 Inputs: 160 salt optional salt value (a non-secret random value); 161 if not provided, it is set to a string of 64 zeros. 162 IKM input keying material 163 info optional context and application specific information 164 (can be a zero-length string) 165 L length of output keying material in octets 166 (<= 255*32 = 8160) 167 168 Output: 169 OKM output keying material (of L octets) 170 ]]></artwork> 171 <t>The output OKM is calculated as follows:</t> 172 <artwork><![CDATA[ 173 PRK = HKDF-Extract(salt, IKM) with Hash = SHA-512 (HashLen = 64) 174 OKM = HKDF-Expand(PRK, info, L) with Hash = SHA-256 (HashLen = 32) 175 ]]></artwork> 176 </section> 177 <section anchor="hkdf-mod"> 178 <name>HKDF-Mod</name> 179 <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> 180 <artwork><![CDATA[ 181 HKDF-Mod(N, salt, IKM, info) -> OKM 182 183 Inputs: 184 N multiple precision integer 185 salt optional salt value (a non-secret random value); 186 if not provided, it is set to a string of 64 zeros. 187 IKM input keying material 188 info optional context and application specific information 189 (can be a zero-length string) 190 191 Output: 192 OKM output keying material (smaller than N) 193 ]]></artwork> 194 <t>The final output <tt>OKM</tt> is determined deterministically based on a counter initialized at zero.</t> 195 <artwork><![CDATA[ 196 counter = 0 197 do until OKM < N: 198 x = HKDF(salt, IKM, info | uint16(counter), bytes(N)) 199 OKM = uint(bits(N), x) 200 counter += 1 201 ]]></artwork> 202 </section> 203 </section> 204 <section anchor="non-blind-signatures"> 205 <name>Non-Blind Signatures</name> 206 <section anchor="ed25519"> 207 <name>Ed25519</name> 208 </section> 209 </section> 210 <section anchor="blind-signatures"> 211 <name>Blind Signatures</name> 212 <section anchor="rsa-fdh"> 213 <name>RSA-FDH</name> 214 <section anchor="supporting-functions"> 215 <name>Supporting Functions</name> 216 <artwork><![CDATA[ 217 RSA-FDH(msg, pubkey) -> fdh 218 219 Inputs: 220 msg message 221 pubkey RSA public key consisting of modulus N and public exponent e 222 223 Output: 224 fdh full-domain hash of msg over pubkey.N 225 ]]></artwork> 226 <t><tt>fdh</tt> is calculated based on HKDF-Mod from <xref target="hkdf-mod"/> as follows:</t> 227 <artwork><![CDATA[ 228 info = "RSA-FDA FTpsW!" 229 salt = uint16(bytes(pubkey.N)) | uint16(bytes(pubkey.e)) 230 | pubkey.N | pubkey.e 231 fdh = HKDF-Mod(pubkey.N, salt, msg, info) 232 ]]></artwork> 233 <t>The resulting <tt>fdh</tt> can be used to test against a malicious RSA pubkey 234 by verifying that the greatest common denominator (gcd) of <tt>fdh</tt> and <tt>pubkey.N</tt> is 1.</t> 235 <artwork><![CDATA[ 236 RSA-FDH-Derive(bks, pubkey) -> out 237 238 Inputs: 239 bks blinding key secret of length L = 32 octets 240 pubkey RSA public key consisting of modulus N and public exponent e 241 242 Output: 243 out full-domain hash of bks over pubkey.N 244 ]]></artwork> 245 <t><tt>out</tt> is calculated based on HKDF-Mod from <xref target="hkdf-mod"/> as follows:</t> 246 <artwork><![CDATA[ 247 info = "Blinding KDF" 248 salt = "Blinding KDF extractor HMAC key" 249 fdh = HKDF-Mod(pubkey.N, salt, bks, info) 250 ]]></artwork> 251 </section> 252 <section anchor="blinding"> 253 <name>Blinding</name> 254 <artwork><![CDATA[ 255 RSA-FDH-Blind(msg, bks, pubkey) -> out 256 257 Inputs: 258 msg message 259 bks blinding key secret of length L = 32 octets 260 pubkey RSA public key consisting of modulus N and public exponent e 261 262 Output: 263 out message blinded for pubkey 264 ]]></artwork> 265 <t><tt>out</tt> is calculated based on RSA-FDH from <xref target="rsa-fdh"/> as follows:</t> 266 <artwork><![CDATA[ 267 data = RSA-FDH(msg, pubkey) 268 r = RSA-FDH-Derive(bks, pubkey) 269 r_e = r ** pubkey.e (mod pubkey.N) 270 out = r_e * data (mod pubkey.N) 271 ]]></artwork> 272 </section> 273 <section anchor="signing"> 274 <name>Signing</name> 275 <artwork><![CDATA[ 276 RSA-FDH-Sign(data, privkey) -> sig 277 278 Inputs: 279 data data to be signed, an integer smaller than privkey.N 280 privkey RSA private key consisting of modulus N and private exponent d 281 282 Output: 283 sig signature on data by privkey 284 ]]></artwork> 285 <t><tt>sig</tt> is calculated as follows:</t> 286 <artwork><![CDATA[ 287 sig = data ** privkey.d (mod privkey.N) 288 ]]></artwork> 289 </section> 290 <section anchor="unblinding"> 291 <name>Unblinding</name> 292 <artwork><![CDATA[ 293 RSA-FDH-Unblind(sig, bks, pubkey) -> out 294 295 Inputs: 296 sig blind signature 297 bks blinding key secret of length L = 32 octets 298 pubkey RSA public key consisting of modulus N and public exponent e 299 300 Output: 301 out unblinded signature 302 ]]></artwork> 303 <t><tt>out</tt> is calculated as follows:</t> 304 <artwork><![CDATA[ 305 r = RSA-FDH-Derive(bks, pubkey) 306 r_inv = inverse of r (mod pubkey.N) 307 out = sig * r_inv (mod pubkey.N) 308 ]]></artwork> 309 </section> 310 <section anchor="verifying"> 311 <name>Verifying</name> 312 <artwork><![CDATA[ 313 RSA-FDH-Verify(msg, sig, pubkey) -> out 314 315 Inputs: 316 msg message 317 sig signature of pubkey over msg 318 pubkey RSA public key consisting of modulus N and public exponent e 319 320 Output: 321 out true, if sig is a valid signature 322 ]]></artwork> 323 <t><tt>out</tt> is calculated based on RSA-FDH from <xref target="rsa-fdh"/> as follows:</t> 324 <artwork><![CDATA[ 325 data = RSA-FDH(msg, pubkey) 326 exp = sig ** pubkey.e (mod pubkey.N) 327 out = (data == exp) 328 ]]></artwork> 329 </section> 330 </section> 331 <section anchor="clause-schnorr"> 332 <name>Clause-Schnorr</name> 333 </section> 334 </section> 335 </section> 336 <section anchor="datatypes"> 337 <name>Datatypes</name> 338 <section anchor="amount"> 339 <name>Amount</name> 340 <t>Amounts are represented in Taler as positive fixed-point values 341 consisting of <tt>value</tt> as the non-negative integer part of the base currency, 342 the <tt>fraction</tt> given in units of one hundred millionth (1e-8) of the base currency, 343 and <tt>currency</tt> as the 3-11 ASCII characters identifying the currency.</t> 344 <t>Whenever used in the protocol, the binary representation of an <tt>amount</tt> is 345 <tt>uint64(amount.value) | uint32(amount.fraction) | padZero(12, amount.currency)</tt>.</t> 346 </section> 347 <section anchor="timestamps"> 348 <name>Timestamps</name> 349 <t>Absolute timestamps are represented as <tt>uint64(x)</tt> where <tt>x</tt> corresponds to 350 the microseconds since <tt>1970-01-01 00:00 CEST</tt> (the UNIX epoch). 351 The special value <tt>0xFFFFFFFFFFFFFFFF</tt> represents "never". 352 <!-- 353 // todo: check if needed and correct 354 Relative timestamps are represented as `uint64(x)` where `x` is given in microseconds. 355 The special value `0xFFFFFFFFFFFFFFFF` represents "forever". 356 --> 357 </t> 358 </section> 359 <section anchor="signatures"> 360 <name>Signatures</name> 361 <t>All messages to be signed in Taler start with a header containing their size and 362 a fixed signing context (purpose) as registered by GANA in the 363 <eref target="https://gana.gnunet.org/gnunet-signatures/gnunet_signatures.html">GNUnet Signature Purposes</eref> 364 registry. Taler-related purposes start at 1000.</t> 365 <artwork><![CDATA[ 366 Sign-Msg(purpose, msg) -> out 367 368 Inputs: 369 purpose signature purpose as registered at GANA 370 msg message content (excl. header) to be signed 371 372 Output: 373 out complete message (incl. header) to be signed 374 ]]></artwork> 375 <t><tt>out</tt> is formed as follows:</t> 376 <artwork><![CDATA[ 377 out = uint32(len(msg)) | uint32(purpose) | msg 378 ]]></artwork> 379 <t>// todo: explain persist, check, knows, sum, indexing (if left of equal sign, single entry; if not refers to whole list)</t> 380 </section> 381 </section> 382 <section anchor="the-taler-crypto-protocol"> 383 <name>The Taler Crypto Protocol</name> 384 <section anchor="withdrawal"> 385 <name>Withdrawal</name> 386 <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, 387 attributing value to the coins according to <tt>n</tt> chosen denominations (<tt>denomᵢ</tt>). 388 The total value and withdrawal fee (defined by the exchange per denomination) 389 must be smaller or equal to the amount stored in the single reserve used for withdrawal.</t> 390 <t>// todo: extend with extra roundtrip for CBS</t> 391 <artwork><![CDATA[ 392 wallet exchange 393 knows denomᵢ.pub knows denomᵢ.priv 394 | | 395 +-----------------------------+ | 396 | (W1) reserve key generation | | 397 +-----------------------------+ | 398 | | 399 |----------- (bank transfer) ----------->| 400 | (subject: reserve.pub, amount: value) | 401 | | 402 | +------------------------------+ 403 | | persist (reserve.pub, value) | 404 | +------------------------------+ 405 | | 406 +-----------------------------------+ | 407 | (W2) coin generation and blinding | | 408 +-----------------------------------+ | 409 | | 410 |-------------- /withdraw -------------->| 411 | (reserve.pub, ~(coinᵢ.h_denom), | 412 | ~blind_coin, sig0) | 413 | | 414 | +--------------------------------+ 415 | | (E1) coin issuance and signing | 416 | +--------------------------------+ 417 | | 418 |<----------- (~blind_sig) --------------| 419 | | 420 +----------------------+ | 421 | (W3) coin unblinding | | 422 +----------------------+ | 423 | | 424 ]]></artwork> 425 <t>where (for RSA, without age-restriction)</t> 426 <artwork><![CDATA[ 427 (W1) reserve key generation (wallet) 428 429 reserve = EdDSA-Keygen() 430 persist (reserve, value) 431 ]]></artwork> 432 <t>The wallet derives coins and blinding secrets using a HKDF from a single master secret per withdrawal operation, 433 together with an integer index. 434 This is strictly speaking an implementation detail since the master secret is never revealed to any other party, 435 and might be chosen to be implemented differently.</t> 436 <artwork><![CDATA[ 437 (W2) coin generation and blinding (wallet) 438 439 master_secret = random(256) 440 persist master_secret 441 coin_seedᵢ = HKDF(uint32(i), master_secret, "taler-withdrawal-coin-derivation", 64) 442 blind_secretᵢ = coin_seedᵢ[32:] 443 coinᵢ.priv = coin_seedᵢ[:32] 444 coinᵢ.pub = EdDSA-GetPub(coinᵢ.priv) 445 coinᵢ.h_denom = SHA-512(uint32(0) | uint32(1) | denomᵢ.pub) 446 blind_coinᵢ = RSA-FDH-Blind(SHA-512(coinᵢ.pub), blind_secretᵢ, denomᵢ.pub) 447 msg = Sign-Msg(WALLET_RESERVE_WITHDRAW, 448 ( sum(denomᵢ.value) | sum(denomᵢ.fee_withdraw) 449 | SHA-512( SHA-512(~(denomᵢ.pub)) | uint32(0x1) | blind_coinᵢ ) 450 | uint256(0x0) | uint32(0x0) | uint32(0x0) )) 451 sig = EdDSA-Sign(reserve.priv, msg) 452 ]]></artwork> 453 <artwork><![CDATA[ 454 (E1) coin issuance and signing (exchange) 455 456 denomᵢ = Denom-Lookup(coinᵢ.h_denom) 457 check denomᵢ.pub known and not withdrawal-expired 458 check EdDSA-Verify(reserve.pub, msg, sig) 459 check reserve KYC status ok or not needed 460 total = sum(~(denomᵢ.value)) + sum(~(denomᵢ.fee_withdraw)) 461 check reserve.balance >= total 462 reserve.balance -= total 463 blind_sigᵢ = RSA-FDH-Sign(blind_coinᵢ, denomᵢ.priv) 464 persist withdrawal 465 ]]></artwork> 466 <artwork><![CDATA[ 467 (W4) coin unblinding (wallet) 468 469 coinᵢ.sig = RSA-FDH-Unblind(blind_sigᵢ, blind_secretᵢ, denomᵢ.pub) 470 check RSA-FDH-Verify(SHA-512(coinᵢ.pub), coinᵢ.sig, denomᵢ.pub) 471 persist (coinᵢ, blind_secretᵢ) 472 ]]></artwork> 473 </section> 474 <section anchor="payment"> 475 <name>Payment</name> 476 <t>The wallet obtains <tt>contract</tt> information for an <tt>order</tt> from the merchant 477 after claiming it with a <tt>nonce</tt>. 478 Payment of the order is prepared by signing (partial) deposit authorizations (<tt>depositᵢ</tt>) of coins (<tt>coinᵢ</tt>), 479 where the sum of all contributions (<tt>contributionᵢ <= denomᵢ.value</tt>) must match the <tt>contract.price</tt> plus potential deposit fees. 480 The payment is complete as soon as the merchant successfully redeems the deposit authorizations at the exchange (cf. <xref target="deposit"/>).</t> 481 <artwork><![CDATA[ 482 wallet merchant 483 knows valid coinᵢ knows merchant.priv 484 knows exchange, payto 485 | | 486 | +-----------------------+ 487 | | (M1) order generation | 488 | +-----------------------+ 489 | | 490 |<------- (QR-Code / NFC / URI) ---------| 491 | (order.{id,token?}) | 492 | | 493 +-----------------------+ | 494 | (W1) nonce generation | | 495 +-----------------------+ | 496 | | 497 |------- /orders/{order.id}/claim ------>| 498 | (nonce.pub, order.token?) | 499 | | 500 | +--------------------------+ 501 | | (M2) contract generation | 502 | +--------------------------+ 503 | | 504 |<---- (contract, merchant.pub, contract_sig) ----| 505 | | 506 +--------------------------+ | 507 | (W2) payment preparation | | 508 +--------------------------+ | 509 | | 510 |------- /orders/{order.id}/pay -------->| 511 | (~deposit) | 512 | | 513 | +--------------------+ 514 | | (M3) deposit check | 515 | +--------------------+ 516 | | 517 |<--------------- (sig) -----------------| 518 | | 519 +---------------------------+ | 520 | (W3) payment verification | | 521 +---------------------------+ | 522 | | 523 ]]></artwork> 524 <t>where (without age restriction, policy and wallet data hash)</t> 525 <artwork><![CDATA[ 526 (M1) order generation (merchant) 527 528 wire_salt = random(128) 529 persist order = (id, price, info, token?, wire_salt) 530 ]]></artwork> 531 <artwork><![CDATA[ 532 (W1) nonce generation (wallet) 533 534 nonce = EdDSA-Keygen() 535 persist nonce.priv 536 ]]></artwork> 537 <t>Note that the private key of <tt>nonce</tt> is currently not used anywhere in the protocol. 538 However, it could be used in the future to prove ownership of an order transaction, 539 enabling use-cases such as "unclaiming" or transferring an order to another person, 540 or proving the payment without resorting to the individual coins.</t> 541 <artwork><![CDATA[ 542 (M2) contract generation (merchant) 543 544 h_wire = HKDF(wire_salt, payto, "merchant-wire-signature", 64) 545 determine timestamp, refund_deadline, wire_deadline 546 contract = (order.{id,price,info,token?}, exchange, h_wire, timestamp, refund_deadline, wire_deadline) 547 check contract.order.token == token 548 contract.nonce = nonce.pub 549 persist contract 550 h_contract = SHA-512(canonicalJSON(contract)) 551 msg = Sign-Msg(MERCHANT_CONTRACT, h_contract) 552 contract_sig = EdDSA-Sign(merchant.priv, msg) 553 ]]></artwork> 554 <artwork><![CDATA[ 555 (W2) payment preparation (wallet) 556 557 h_contract = SHA-512(canonicalJSON(contract)) 558 msg = Sign-Msg(MERCHANT_CONTRACT, h_contract) 559 check EdDSA-Verify(merchant.pub, msg, contract_sig) 560 check contract.nonce = nonce 561 TODO: double-check extra hash check? 562 ~selection = CoinSelection(contract.{exchange,price}) TODO: include MarkDirty here 563 (coinᵢ, denomᵢ, contributionᵢ) = selectionᵢ 564 h_contract = SHA-512(canonicalJSON(contract)) 565 msgᵢ = Sign-Msg(WALLET_COIN_DEPOSIT, 566 ( h_contract | uint256(0x0) 567 | uint512(0x0) | contract.h_wire | coinᵢ.h_denom 568 | contract.timestamp | contract.refund_deadline 569 | contributionᵢ + denomᵢ.fee_deposit 570 | denomᵢ.fee_deposit | merchant.pub | uint512(0x0) )) 571 sigᵢ = EdDSA-Sign(coinᵢ.priv, msgᵢ) 572 depositᵢ = (coinᵢ.{pub,sig,h_denom}, contributionᵢ, sigᵢ) 573 persist (contract, ~sig, ~deposit) 574 ]]></artwork> 575 <t>// TODO: explain CoinSelection 576 // TODO: maybe better {sigᵢ} instead of ~sig? 577 // TODO: maybe introduce symbol for pub/priv 578 // TODO: maybe rename Sign-Msg as name is currently a bit confusing</t> 579 <artwork><![CDATA[ 580 (M3) deposit check (merchant) 581 582 check sum(depositᵢ.contribution) == contract.price 583 check Deposit(~deposit) 584 msg = Sign-Msg(MERCHANT_PAYMENT_OK, h_contract) 585 sig = EdDSA-Sign(merchant.priv, msg) 586 ]]></artwork> 587 <artwork><![CDATA[ 588 (W3) payment verification (wallet) 589 590 msg = Sign-Msg(MERCHANT_PAYMENT_OK, h_contract) 591 check EdDSA-Verify(merchant.pub, msg, sig) 592 ]]></artwork> 593 </section> 594 <section anchor="deposit"> 595 <name>Deposit</name> 596 <t>// todo: add introductory text</t> 597 <artwork><![CDATA[ 598 merchant/wallet exchange 599 knows exchange.pub knows exchange.priv 600 knows contract_sig knows denomᵢ.pub 601 knows payto, wire_salt | 602 knows contract, ~deposit | 603 | | 604 +--------------------------+ | 605 | (M1) deposit preparation | | 606 +--------------------------+ | 607 | | 608 |----------- /batch-deposit ------------>| 609 | (info, h_contract, ~deposit | 610 | merchant.pub, contract_sig) | 611 | | 612 | +-------------------------+ 613 | | (E1) deposit validation | 614 | +-------------------------+ 615 | | 616 |<--- (timestamp, exchange.pub, sig) ----| 617 | | 618 +---------------------------+ | 619 | (M2) deposit verification | | 620 +---------------------------+ | 621 | | 622 ]]></artwork> 623 <t>where (without age restriction, policy and wallet data hash)</t> 624 <artwork><![CDATA[ 625 (M1) Deposit preparation (merchant/wallet) 626 627 h_contract = SHA-512(canonicalJSON(contract)) 628 info.time = contract.{timestamp, wire_deadline, refund_deadline} 629 info.wire = (payto, wire_salt) 630 ]]></artwork> 631 <artwork><![CDATA[ 632 (E1) Deposit validation (exchange) 633 634 coinᵢ = depositᵢ.coin 635 denomᵢ = Denom-Lookup(coinᵢ.h_denom) 636 check denomᵢ.pub known and not deposit-expired 637 h_wire = HKDF(info.wire.wire_salt, info.wire.payto, "merchant-wire-signature", 64) 638 msgᵢ = Sign-Msg(WALLET_COIN_DEPOSIT, 639 ( h_contract | uint256(0x0) 640 | uint512(0x0) | h_wire | coinᵢ.h_denom 641 | info.time.timestamp | info.time.refund_deadline 642 | depositᵢ.contribution + denomᵢ.fee_deposit 643 | denomᵢ.fee_deposit | merchant.pub | uint512(0x0) )) 644 check EdDSA-Verify(coinᵢ.pub, msgᵢ, depositᵢ.sig) 645 check RSA-FDH-Verify(SHA-512(coinᵢ.pub), coinᵢ.sig, denomᵢ.pub) 646 check not overspending 647 persist deposit-record, mark-spent 648 schedule bank transfer to payto 649 timestamp = now() 650 msg = Sign-Msg(EXCHANGE_CONFIRM_DEPOSIT, 651 ( h_contract | h_wire | uint512(0x0) 652 | timestamp | info.time.wire_deadline 653 | info.time.refund_deadline 654 | sum(depositᵢ.contribution) - sum(denomᵢ.fee_deposit) 655 | SHA-512(depositᵢ.sig) | merchant.pub )) 656 sig = EdDSA-Sign(exchange.priv, msg) 657 ]]></artwork> 658 <artwork><![CDATA[ 659 (M2) Deposit verification (merchant/wallet) 660 661 h_wire = HKDF(wire_salt, payto, "merchant-wire-signature", 64) 662 msg = Sign-Msg(EXCHANGE_CONFIRM_DEPOSIT, 663 ( h_contract | h_wire | uint512(0x0) 664 | timestamp | contract.wire_deadline 665 | contract.refund_deadline 666 | sum(depositᵢ.contribution) - sum(denomᵢ.fee_deposit) 667 | SHA-512(depositᵢ.sig) | merchant.pub )) 668 check EdDSA-Verify(exchange.pub, msg, sig) 669 ]]></artwork> 670 </section> 671 <section anchor="refresh"> 672 <name>Refresh</name> 673 <t>// todo</t> 674 </section> 675 <section anchor="refund"> 676 <name>Refund</name> 677 <t>// todo</t> 678 </section> 679 <section anchor="recoup"> 680 <name>Recoup</name> 681 <t>// todo</t> 682 </section> 683 <section anchor="w2w-push"> 684 <name>Wallet-to-Wallet Push Payment</name> 685 <t>// todo</t> 686 </section> 687 <section anchor="w2w-pull"> 688 <name>Wallet-to-Wallet Pull Payment</name> 689 <t>// todo</t> 690 </section> 691 </section> 692 <section anchor="security-considerations"> 693 <name>Security Considerations</name> 694 <t>[ TBD ]</t> 695 </section> 696 <section anchor="iana-considerations"> 697 <name>IANA Considerations</name> 698 <t>None.</t> 699 </section> 700 </middle> 701 <back> 702 <references anchor="sec-normative-references"> 703 <name>Normative References</name> 704 <reference anchor="RFC20"> 705 <front> 706 <title>ASCII format for network interchange</title> 707 <author fullname="V.G. Cerf" initials="V.G." surname="Cerf"/> 708 <date month="October" year="1969"/> 709 </front> 710 <seriesInfo name="STD" value="80"/> 711 <seriesInfo name="RFC" value="20"/> 712 <seriesInfo name="DOI" value="10.17487/RFC0020"/> 713 </reference> 714 <reference anchor="RFC2104"> 715 <front> 716 <title>HMAC: Keyed-Hashing for Message Authentication</title> 717 <author fullname="H. Krawczyk" initials="H." surname="Krawczyk"/> 718 <author fullname="M. Bellare" initials="M." surname="Bellare"/> 719 <author fullname="R. Canetti" initials="R." surname="Canetti"/> 720 <date month="February" year="1997"/> 721 <abstract> 722 <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> 723 </abstract> 724 </front> 725 <seriesInfo name="RFC" value="2104"/> 726 <seriesInfo name="DOI" value="10.17487/RFC2104"/> 727 </reference> 728 <reference anchor="RFC5869"> 729 <front> 730 <title>HMAC-based Extract-and-Expand Key Derivation Function (HKDF)</title> 731 <author fullname="H. Krawczyk" initials="H." surname="Krawczyk"/> 732 <author fullname="P. Eronen" initials="P." surname="Eronen"/> 733 <date month="May" year="2010"/> 734 <abstract> 735 <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> 736 </abstract> 737 </front> 738 <seriesInfo name="RFC" value="5869"/> 739 <seriesInfo name="DOI" value="10.17487/RFC5869"/> 740 </reference> 741 <reference anchor="RFC6234"> 742 <front> 743 <title>US Secure Hash Algorithms (SHA and SHA-based HMAC and HKDF)</title> 744 <author fullname="D. Eastlake 3rd" initials="D." surname="Eastlake 3rd"/> 745 <author fullname="T. Hansen" initials="T." surname="Hansen"/> 746 <date month="May" year="2011"/> 747 <abstract> 748 <t>Federal Information Processing Standard, FIPS</t> 749 </abstract> 750 </front> 751 <seriesInfo name="RFC" value="6234"/> 752 <seriesInfo name="DOI" value="10.17487/RFC6234"/> 753 </reference> 754 <reference anchor="HKDF"> 755 <front> 756 <title>Cryptographic Extraction and Key Derivation: The HKDF Scheme</title> 757 <author fullname="Hugo Krawczyk" initials="H." surname="Krawczyk"> 758 <organization/> 759 </author> 760 <date year="2010"/> 761 </front> 762 <seriesInfo name="Lecture Notes in Computer Science" value="pp. 631-648"/> 763 <seriesInfo name="DOI" value="10.1007/978-3-642-14623-7_34"/> 764 <seriesInfo name="ISBN" value="["9783642146220", "9783642146237"]"/> 765 <refcontent>Springer Berlin Heidelberg</refcontent> 766 </reference> 767 <reference anchor="SHS"> 768 <front> 769 <title>Secure hash standard</title> 770 <author> 771 <organization/> 772 </author> 773 <date year="2015"/> 774 </front> 775 <seriesInfo name="DOI" value="10.6028/nist.fips.180-4"/> 776 <refcontent>National Institute of Standards and Technology (U.S.)</refcontent> 777 </reference> 778 </references> 779 <?line 732?> 780 781 <section anchor="change-log"> 782 <name>Change log</name> 783 </section> 784 <section numbered="false" anchor="acknowledgments"> 785 <name>Acknowledgments</name> 786 <t>[ TBD ]</t> 787 <t>This work was supported in part by the German Federal Ministry of 788 Education and Research (BMBF) within the project Concrete Contracts.</t> 789 </section> 790 </back> 791 <!-- ##markdown-source: 792 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 932 R+AFyWLSsv4XcFI2TK9YAAA= 933 934 --> 935 936 </rfc>