lsd0009

LSD0009: The GNU Taler Protocol
Log | Files | Refs | README

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.