draft-guetschow-taler-protocol.md (20208B)
1 --- 2 v: 3 3 4 title: "The GNU Taler Protocol" 5 docname: draft-guetschow-taler-protocol 6 category: info 7 8 ipr: trust200902 9 workgroup: independent 10 stream: independent 11 keyword: 12 - taler 13 - cryptography 14 - ecash 15 - payments 16 17 #venue: 18 # repo: https://git.gnunet.org/lsd0009.git/ 19 # latest: https://lsd.gnunet.org/lsd0009/ 20 21 author: 22 - 23 name: Mikolai Gütschow 24 org: TUD Dresden University of Technology 25 abbrev: TU Dresden 26 street: Helmholtzstr. 10 27 city: Dresden 28 code: D-01069 29 country: Germany 30 email: mikolai.guetschow@tu-dresden.de 31 32 normative: 33 RFC20: 34 RFC2104: 35 RFC5869: 36 RFC6234: 37 HKDF: DOI.10.1007/978-3-642-14623-7_34 38 SHS: DOI.10.6028/NIST.FIPS.180-4 39 40 informative: 41 42 43 --- abstract 44 45 \[ TBW \] 46 47 --- middle 48 49 # Introduction 50 51 \[ TBW \] 52 53 Beware that this document is still work-in-progress and may contain errors. 54 Use at your own risk! 55 56 # Notation 57 58 - `"abc"` denotes the literal string `abc` encoded as ASCII [RFC20] 59 - `a | b` denotes the concatenation of a with b 60 - `len(a)` denotes the length in bytes of the byte string a 61 - `padZero(y, a)` denotes the byte string a, zero-padded to the length of y bytes 62 - `bits(x)`/`bytes(x)` denotes the minimal number of bits/bytes necessary to represent the multiple precision integer x 63 - `uint(y, x)` denotes the `y` least significant bits of the integer `x` encoded in network byte order (big endian) 64 - `uint16(x)`/`uint32(x)`/`uint64(x)`/`uint256(x)`/`uint512(x)` is equivalent to `uint(16, x)`/`uint(32, x)`/`uint(64, x)`/`uint(256, x)`/`uint(512, x)`, respectively 65 - `random(y)` denotes a randomly generated sequence of y bits 66 - `a * b (mod N)` / `a ** b (mod N)` denotes the multiplication / exponentiation of multiple precision integers a and b, modulo N 67 68 # Cryptographic Primitives 69 70 ## Cryptographic Hash Functions 71 72 ### SHA-256 {#sha256} 73 74 ~~~ 75 SHA-256(msg) -> hash 76 77 Input: 78 msg input message of length L < 2^61 octets 79 80 Output: 81 hash message digest of fixed length HashLen = 32 octets 82 ~~~ 83 84 `hash` is the output of SHA-256 as per Sections 4.1, 5.1, 6.1, and 6.2 of [RFC6234]. 85 86 ### SHA-512 {#sha512} 87 88 ~~~ 89 SHA-512(msg) -> hash 90 91 Input: 92 msg input message of length L < 2^125 octets 93 94 Output: 95 hash message digest of fixed length HashLen = 64 octets 96 ~~~ 97 98 `hash` is the output of SHA-512 as per Sections 4.2, 5.2, 6.3, and 6.4 of [RFC6234]. 99 100 ### SHA-512-256 (truncated SHA-512) {#sha512-trunc} 101 102 ~~~ 103 SHA-512-256(msg) -> hash 104 105 Input: 106 msg input message of length L < 2^125 octets 107 108 Output: 109 hash message digest of fixed length HashLen = 32 octets 110 ~~~ 111 112 The output `hash` corresponds to the first 32 octets of the output of SHA-512 defined in {{sha512}}: 113 114 ~~~ 115 temp = SHA-512(msg) 116 hash = temp[0:31] 117 ~~~ 118 119 Note that this operation differs from SHA-512/256 as defined in [SHS] in the initial hash value. 120 121 122 ## Message Authentication Codes 123 124 ### HMAC {#hmac} 125 126 ~~~ 127 HMAC-Hash(key, text) -> out 128 129 Option: 130 Hash cryptographic hash function with output length HashLen 131 132 Input: 133 key secret key of length at least HashLen 134 text input data of arbitary length 135 136 Output: 137 out output of length HashLen 138 ~~~ 139 140 `out` is calculated as defined in [RFC2104]. 141 142 143 ## Key Derivation Functions 144 145 ### HKDF {#hkdf} 146 147 The Hashed Key Derivation Function (HKDF) used in Taler is an instantiation of [RFC5869] 148 with two different hash functions for the Extract and Expand step as suggested in [HKDF]: 149 `HKDF-Extract` uses `HMAC-SHA512`, while `HKDF-Expand` uses `HMAC-SHA256` (cf. {{hmac}}). 150 151 ~~~ 152 HKDF(salt, IKM, info, L) -> OKM 153 154 Inputs: 155 salt optional salt value (a non-secret random value); 156 if not provided, it is set to a string of 64 zeros. 157 IKM input keying material 158 info optional context and application specific information 159 (can be a zero-length string) 160 L length of output keying material in octets 161 (<= 255*32 = 8160) 162 163 Output: 164 OKM output keying material (of L octets) 165 ~~~ 166 167 The output OKM is calculated as follows: 168 169 ~~~ 170 PRK = HKDF-Extract(salt, IKM) with Hash = SHA-512 (HashLen = 64) 171 OKM = HKDF-Expand(PRK, info, L) with Hash = SHA-256 (HashLen = 32) 172 ~~~ 173 174 ### HKDF-Mod 175 176 Based on the HKDF defined in {{hkdf}}, this function returns an OKM that is smaller than a given multiple precision integer N. 177 178 ~~~ 179 HKDF-Mod(N, salt, IKM, info) -> OKM 180 181 Inputs: 182 N multiple precision integer 183 salt optional salt value (a non-secret random value); 184 if not provided, it is set to a string of 64 zeros. 185 IKM input keying material 186 info optional context and application specific information 187 (can be a zero-length string) 188 189 Output: 190 OKM output keying material (smaller than N) 191 ~~~ 192 193 The final output `OKM` is determined deterministically based on a counter initialized at zero. 194 195 ~~~ 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 ~~~ 202 203 ## Non-Blind Signatures 204 205 ### Ed25519 206 207 ## Blind Signatures 208 209 ### RSA-FDH {#rsa-fdh} 210 211 #### Supporting Functions 212 213 ~~~ 214 RSA-FDH(msg, pubkey) -> fdh 215 216 Inputs: 217 msg message 218 pubkey RSA public key consisting of modulus N and public exponent e 219 220 Output: 221 fdh full-domain hash of msg over pubkey.N 222 ~~~ 223 224 `fdh` is calculated based on HKDF-Mod from {{hkdf-mod}} as follows: 225 226 ~~~ 227 info = "RSA-FDA FTpsW!" 228 salt = uint16(bytes(pubkey.N)) | uint16(bytes(pubkey.e)) 229 | pubkey.N | pubkey.e 230 fdh = HKDF-Mod(pubkey.N, salt, msg, info) 231 ~~~ 232 233 The resulting `fdh` can be used to test against a malicious RSA pubkey 234 by verifying that the greatest common denominator (gcd) of `fdh` and `pubkey.N` is 1. 235 236 ~~~ 237 RSA-FDH-Derive(bks, pubkey) -> out 238 239 Inputs: 240 bks blinding key secret of length L = 32 octets 241 pubkey RSA public key consisting of modulus N and public exponent e 242 243 Output: 244 out full-domain hash of bks over pubkey.N 245 ~~~ 246 247 `out` is calculated based on HKDF-Mod from {{hkdf-mod}} as follows: 248 249 ~~~ 250 info = "Blinding KDF" 251 salt = "Blinding KDF extractor HMAC key" 252 fdh = HKDF-Mod(pubkey.N, salt, bks, info) 253 ~~~ 254 255 #### Blinding 256 257 ~~~ 258 RSA-FDH-Blind(msg, bks, pubkey) -> out 259 260 Inputs: 261 msg message 262 bks blinding key secret of length L = 32 octets 263 pubkey RSA public key consisting of modulus N and public exponent e 264 265 Output: 266 out message blinded for pubkey 267 ~~~ 268 269 `out` is calculated based on RSA-FDH from {{rsa-fdh}} as follows: 270 271 ~~~ 272 data = RSA-FDH(msg, pubkey) 273 r = RSA-FDH-Derive(bks, pubkey) 274 r_e = r ** pubkey.e (mod pubkey.N) 275 out = r_e * data (mod pubkey.N) 276 ~~~ 277 278 #### Signing 279 280 ~~~ 281 RSA-FDH-Sign(data, privkey) -> sig 282 283 Inputs: 284 data data to be signed, an integer smaller than privkey.N 285 privkey RSA private key consisting of modulus N and private exponent d 286 287 Output: 288 sig signature on data by privkey 289 ~~~ 290 291 `sig` is calculated as follows: 292 293 ~~~ 294 sig = data ** privkey.d (mod privkey.N) 295 ~~~ 296 297 #### Unblinding 298 299 ~~~ 300 RSA-FDH-Unblind(sig, bks, pubkey) -> out 301 302 Inputs: 303 sig blind signature 304 bks blinding key secret of length L = 32 octets 305 pubkey RSA public key consisting of modulus N and public exponent e 306 307 Output: 308 out unblinded signature 309 ~~~ 310 311 `out` is calculated as follows: 312 313 ~~~ 314 r = RSA-FDH-Derive(bks, pubkey) 315 r_inv = inverse of r (mod pubkey.N) 316 out = sig * r_inv (mod pubkey.N) 317 ~~~ 318 319 #### Verifying 320 321 ~~~ 322 RSA-FDH-Verify(msg, sig, pubkey) -> out 323 324 Inputs: 325 msg message 326 sig signature of pubkey over msg 327 pubkey RSA public key consisting of modulus N and public exponent e 328 329 Output: 330 out true, if sig is a valid signature 331 ~~~ 332 333 `out` is calculated based on RSA-FDH from {{rsa-fdh}} as follows: 334 335 ~~~ 336 data = RSA-FDH(msg, pubkey) 337 exp = sig ** pubkey.e (mod pubkey.N) 338 out = (data == exp) 339 ~~~ 340 341 ### Clause-Schnorr 342 343 # The Taler Crypto Protocol 344 345 ## Datatypes 346 347 ### Amount 348 349 Amounts are represented in Taler as positive fixed-point values 350 consisting of `value` as the non-negative integer part of the base currency, 351 the `fraction` given in units of one hundred millionth (1e-8) of the base currency, 352 and `currency` as the 3-11 ASCII characters identifying the currency. 353 354 Whenever used in the protocol, the binary representation of an `amount` is 355 `uint64(amount.value) | uint32(amount.fraction) | padZero(12, amount.currency)`. 356 357 ### Timestamps 358 359 Absolute timestamps are represented as `uint64(x)` where `x` corresponds to 360 the microseconds since `1970-01-01 00:00 CEST` (the UNIX epoch). 361 The special value `0xFFFFFFFFFFFFFFFF` represents "never". 362 <!-- 363 // todo: check if needed and correct 364 Relative timestamps are represented as `uint64(x)` where `x` is given in microseconds. 365 The special value `0xFFFFFFFFFFFFFFFF` represents "forever". 366 --> 367 368 ### Signatures 369 370 All messages to be signed in Taler start with a header containing their size and 371 a fixed signing context (purpose) as registered by GANA in the 372 [GNUnet Signature Purposes](https://gana.gnunet.org/gnunet-signatures/gnunet_signatures.html) 373 registry. All Taler-related purposes start at 1000 and can be found in the 374 [registry sources](https://git.taler.net/gana.git/tree/gnunet-signatures/registry.rec#n221). 375 376 ~~~ 377 Sign-Msg(purpose, msg) -> out 378 379 Inputs: 380 purpose signature purpose as registered at GANA 381 msg message content (excl. header) to be signed 382 383 Output: 384 out complete message (incl. header) to be signed 385 ~~~ 386 387 `out` is formed as follows: 388 389 ~~~ 390 out = uint32(len(msg)) | uint32(purpose) | msg 391 ~~~ 392 393 // todo: explain persist, check, knows, sum 394 395 ## Withdrawal 396 397 The wallet generates `n > 0` coins (`coin[i]`) and requests `n` signatures (`blind_sig[i]`) from the exchange, 398 attributing value to the coins according to `n` chosen denominations (`denom[i]`). 399 The total value and withdrawal fee (defined by the exchange per denomination) 400 must be smaller or equal to the amount stored in the single reserve used for withdrawal. 401 402 ~~~ 403 wallet exchange 404 knows denom[i].pub knows denom[i].priv 405 | | 406 +----------------------------+ | 407 | (1) reserve key generation | | 408 +----------------------------+ | 409 | | 410 |----------- (bank transfer) ----------->| 411 | (subject: reserve.pub, amount: value) | 412 | | 413 | +------------------------------+ 414 | | persist (reserve.pub, value) | 415 | +------------------------------+ 416 | | 417 +----------------------------------+ | 418 | (2) coin generation and blinding | | 419 +----------------------------------+ | 420 | | 421 |-------------- /withdraw -------------->| 422 | (reserve.pub, coin[i].h_denom, | 423 | blind_coin[i], sig0) | 424 | | 425 | +-------------------------------+ 426 | | (3) coin issuance and signing | 427 | +-------------------------------+ 428 | | 429 |<----------- blind_sig[i] --------------| 430 | | 431 +---------------------+ | 432 | (4) coin unblinding | | 433 +---------------------+ | 434 ~~~ 435 436 where (for RSA, without age-restriction) 437 438 ~~~ 439 (1) reserve key generation (wallet) 440 441 reserve = EdDSA-Keygen() 442 persist (reserve, value) 443 ~~~ 444 445 The wallet derives coins and blinding secrets using a HKDF from a master secret per withdrawal and an integer index. 446 This is strictly speaking an implementation detail since the master secret is never revealed to any other party, 447 and might be chosen to be implemented differently. 448 449 ~~~ 450 (2) coin generation and blinding (wallet) 451 452 master_secret = random(256) 453 persist master_secret 454 coin_seed[i] = HKDF(uint32(i), master_secret, "taler-withdrawal-coin-derivation", 64) 455 blind_secret[i] = coin_seed[i][32:] 456 coin[i].priv = coin_seed[i][:32] 457 coin[i].pub = EdDSA-GetPub(coin[i].priv) 458 coin[i].h_denom = SHA-512(uint32(0) | uint32(1) | denom[i].pub) 459 blind_coin[i] = RSA-FDH-Blind(SHA-512(coin[i].pub), blind_secret[i], denom[i].pub) 460 msg0 = Sign-Msg(WALLET_RESERVE_WITHDRAW, 461 ( sum(denom[i].value) | sum(denom[i].fee_withdraw) 462 | SHA-512( SHA-512(denom[i].pub) | uint32(0x1) | blind_coin[i] ) 463 | uint256(0x0) | uint32(0x0) | uint32(0x0) )) 464 sig0 = EdDSA-Sign(reserve.priv, msg0) 465 ~~~ 466 467 ~~~ 468 (3) coin issuance and signing (exchange) 469 470 denom[i] = Denom-Lookup(coin[i].h_denom) 471 check denom[i].pub known and not withdrawal-expired 472 check EdDSA-Verify(reserve.pub, msg, sig) 473 check reserve KYC status ok or not needed 474 check reserve.balance >= sum(denom[i].value + denom[i].fee_withdraw) 475 reserve.balance -= sum(denom[i].value + denom[i].fee_withdraw) 476 blind_sig[i] = RSA-FDH-Sign(blind_coin[i], denom[i].priv) 477 persist withdrawal 478 ~~~ 479 480 ~~~ 481 (4) coin unblinding (wallet) 482 483 coin[i].sig = RSA-FDH-Unblind(blind_sig[i], blind_secret[i], denom[i].pub) 484 check RSA-FDH-Verify(SHA-512(coin[i].pub), coin[i].sig, denom[i].pub) 485 persist (coin[i], blind_secret[i]) 486 ~~~ 487 488 ## Payment 489 490 ~~~ 491 wallet merchant 492 knows merchant.pub knows merchant.priv 493 knows valid coin[i] knows exchange, payto 494 | | 495 | +----------------------+ 496 | | (1) order generation | 497 | +----------------------+ 498 | | 499 |<-------- (order.{id,token?}) ----------| 500 | | 501 +----------------------+ | 502 | (2) nonce generation | | 503 +----------------------+ | 504 | | 505 |------- /orders/{order.id}/claim ------>| 506 | (nonce.pub, token?) | 507 | | 508 | +-------------------------+ 509 | | (3) contract generation | 510 | +-------------------------+ 511 | | 512 |<----------- contract, sig -------------| 513 | | 514 +-------------------------+ | 515 | (4) payment preparation | | 516 +-------------------------+ | 517 | | 518 |------- /orders/{order.id}/pay -------->| 519 | (deposit[i]) | 520 | | 521 | +-------------------+ 522 | | (5) deposit check | 523 | +-------------------+ 524 | | 525 |<---------------- sig ------------------| 526 | | 527 +--------------------------+ | 528 | (6) payment verification | | 529 +--------------------------+ | 530 ~~~ 531 532 where (without age restriction, policy and wallet data hash) 533 534 ~~~ 535 (1) order generation (merchant) 536 537 wire_salt = random(128) 538 persist order = (id, price, info, token?, wire_salt) 539 ~~~ 540 541 ~~~ 542 (2) nonce generation (wallet) 543 544 nonce = EdDSA-Keygen() 545 persist nonce.priv 546 ~~~ 547 548 Note that the private key of `nonce` is currently not used anywhere in the protocol. 549 However, it could be used in the future to prove ownership of an order transaction, 550 enabling use-cases such as "unclaiming" or transferring an order to another person, 551 or proving the payment without resorting to the individual coins. 552 553 ~~~ 554 (3) contract generation (merchant) 555 556 h_wire = HKDF(wire_salt, payto, "merchant-wire-signature", 64) 557 determine timestamp, refund_deadline, wire_deadline 558 contract = (order.{id,price,info,token?}, exchange, h_wire, timestamp, refund_deadline, wire_deadline) 559 check contract.order.token = token? 560 contract.nonce = nonce.pub 561 persist contract 562 h_contract = SHA-512(canonicalJSON(contract)) 563 msg = Sign-Msg(MERCHANT_CONTRACT, h_contract) 564 sig = EdDSA-Sign(merchant.priv, msg) 565 ~~~ 566 567 ~~~ 568 (4) payment preparation (wallet) 569 570 check EdDSA-Verify(merchant.pub, msg, sig) 571 check contract.nonce = nonce 572 TODO: double-check extra hash check? 573 deposit = CoinSelection(contract.{exchange,price}) TODO: include MarkDirty here 574 msg[i] = Sign-Msg(WALLET_COIN_DEPOSIT, 575 ( h_contract | uint256(0x0) 576 | uint512(0x0) | contract.h_wire | coin[i].h_denom 577 | contract.timestamp | contract.refund_deadline 578 | deposit[i] + denom[i].fee_deposit 579 | denom[i].fee_deposit | merchant.pub | uint512(0x0) )) 580 sig[i] = EdDSA-Sign(coin[i].priv, msg[i]) 581 deposit[i] = (coin[i].{pub,sig,h_denom}, fraction[i], sig[i]) 582 persist (contract, sig[i], deposit[i]) 583 ~~~ 584 585 ~~~ 586 (5) deposit check (merchant) 587 588 check sum(deposit[i].fraction) == contract.price 589 check Deposit(deposit)[i] 590 msg = Sign-Msg(MERCHANT_PAYMENT_OK, h_contract) 591 sig = EdDSA-Sign(merchant.priv, msg) 592 ~~~ 593 594 ~~~ 595 (6) payment verification 596 597 check EdDSA-Verify(merchant.pub, msg, sig) 598 ~~~ 599 600 ## Deposit 601 602 ~~~ 603 merchant/wallet exchange 604 knows exchange.pub knows exchange.priv 605 knows merchant.pub knows *denom.pub 606 knows payto, wire_salt, sig2, h_contract 607 knows contract, *deposit from Payment 608 | | 609 |----------- /batch-deposit ------------>| 610 | (contract.{timestamp,wire_deadline,refund_deadline} 611 | h_contract, merchant.pub, sig2, | 612 | payto, *deposit, wire_salt) | 613 | | 614 | *denom = Denom-Lookup(*deposit.coin.h_denom) 615 | check *denom.pub known and not deposit-expired 616 | contract.h_wire = HKDF(wire_salt, payto, 617 | "merchant-wire-signature", 64) 618 | check *EdDSA-Verify(deposit.coin.pub, msg1, sig1) 619 | check *RSA-FDH-Verify(SHA-512(deposit.coin.pub), 620 | deposit.coin.sig, denom.pub) 621 | check not overspending 622 | persist deposit-record, mark-spent 623 | schedule bank transfer 624 | exchange_timestamp = now() 625 | sig3 = EdDSA-Sign(exchange.priv, msg3) 626 | | 627 |<----- sig3, exchange_timestamp --------| 628 | | 629 check EdDSA-Verify(exchange.pub, msg3, sig3) | 630 ~~~ 631 632 where `msg3` is formed as follows: 633 634 ~~~ 635 msg3 = Sign-Msg(EXCHANGE_CONFIRM_DEPOSIT, 636 ( h_contract | contract.h_wire | uint512(0x0) 637 | exchange_timestamp | contract.wire_deadline 638 | contract.refund_deadline 639 | sum(*deposit.fraction - *denom.fee_deposit) 640 | SHA-512(*deposit.sig1) | merchant.pub )) 641 ~~~ 642 643 # Security Considerations 644 645 \[ TBD \] 646 647 # IANA Considerations 648 649 None. 650 651 --- back 652 653 # Change log 654 655 # Acknowledgments 656 {:numbered="false"} 657 658 \[ TBD \] 659 660 This work was supported in part by the German Federal Ministry of 661 Education and Research (BMBF) within the project Concrete Contracts.