046-mumimo-contracts.rst (26721B)
1 DD 46: Contract Format v1 2 ######################### 3 4 Summary 5 ======= 6 7 The contract v1 format enables a multitude of advanced interactions between 8 merchants and wallets, including donations, subscriptions, coupons, currency 9 exchange and more. 10 11 Motivation 12 ========== 13 14 The existing v0 contract format is too simplistic to 15 support many frequenly requested types of contracts. 16 17 Requirements 18 ============ 19 20 We want Taler to support various interesting use-cases: 21 22 - Unlinkable, uncopyable subscriptions without accounts (reader can pay with 23 Taler to subscribe to online publication, read unlimited number of 24 articles during a certain period, transfer subscription to other devices, 25 maintain unlinkability / full anonymity amongst all anonymous 26 subscribers). 27 28 - Coupons, discounts and stamps -- like receiving a discount on a product, 29 product basket or subscription -- based on previous purchase(s). Again, 30 with unlinkability and anonymity (modulo there being other users eligible 31 for the discount). 32 33 - Subscription tokens lost (due to loss of device without backup) should 34 be recoverable from any previous backup of the subscription. 35 36 - Currency conversion, that is exchanging one currency for another. 37 38 - Donations, including privacy-preserving tax receipts that prove that the 39 user donated to an entity that is eligible for tax-deductions but without 40 revealing which entity the user donated to. At the same time, the entity 41 issuing the tax receipt must be transparent (to the state) with respect to 42 the amount of tax-deductable donations it has received. 43 44 - Throttled political donations where each individual is only allowed to 45 donate anonymously up to a certain amount per year or election cycle. 46 47 - Unlinkable gifts -- enabling the purchase of digital goods (such as 48 articles, albums, etc.) to be consumed by a third party. For example, a 49 newspaper subscription may include a fixed number of articles that can be 50 gifted to others each week, all while maintaining unlinkability and 51 anonymity between the giver and the recipient. 52 53 - Temporally-constrained, unlinkable event ticketing. Allowing visitors to 54 use Taler to purchase a ticket for an event. This ticket grants entry and 55 exit privileges to the event location during a specified time window, while 56 preserving the anonymity of the ticket holder (within the group of all the 57 ticket holders). 58 59 - Event deposit systems. A deposit mechanism for events where customers 60 receive a token alongside their cup or plate, which they are expected to 61 return. This system validates that the cup or plate was legitimately 62 acquired (i.e., not brought from home or stolen from a stack of dirty items) 63 and incentivizes return after use. 64 65 66 Proposed Solution 67 ================= 68 69 Merchants will also blindly sign tokens (not coins) to indicate the 70 eligibility of a user for certain special offers. Contracts will be modified 71 to allow requiring multiple inputs (to be *provisioned* to the merchant) and 72 multiple outputs (to be *yielded* by the merchant). The wallet will then allow 73 the user to select between the choices that the user could pay for, or possibly 74 make an automatic choice if the correct choice is obvious. One output option is 75 blindly signed coins from another exchange, possibly in a different currency. 76 Another output option is blindly signed donation receipts from a DONation 77 AUthority (DONAU). Subscriptions can be modeled by requiring the wallet to 78 provision a token of the same type that is also yielded by the contract. For 79 security, payments using subscription tokens (and possibly certain other special 80 tokens?) will be limited to a list of domains explicitly defined as trusted by 81 the token issuer. When paying for a contract, the wallet must additionally sign 82 over the selected sub-contract index and a hash committing it to the blinded 83 envelopes (if any). The merchant backend will (probably?) need to be changed 84 to truly support multiple currencies (ugh). 85 86 .. _contract-terms-v1: 87 88 New Contract Terms Format 89 ------------------------- 90 91 The contract terms v1 will have the following structure: 92 93 .. ts:def:: DDContractTermsV1 94 95 interface DDContractTermsV1 { 96 // This is version 1, the previous contract terms SHOULD 97 // be indicated using "0", but in v0 specifying the version 98 // is optional. 99 version: 1; 100 101 // Unique, free-form identifier for the proposal. 102 // Must be unique within a merchant instance. 103 // For merchants that do not store proposals in their DB 104 // before the customer paid for them, the ``order_id`` can be used 105 // by the frontend to restore a proposal from the information 106 // encoded in it (such as a short product identifier and timestamp). 107 order_id: string; 108 109 // URL where the same contract could be ordered again (if 110 // available). Returned also at the public order endpoint 111 // for people other than the actual buyer (hence public, 112 // in case order IDs are guessable). 113 public_reorder_url?: string; 114 115 // Time when this contract was generated. 116 timestamp: Timestamp; 117 118 // After this deadline, the merchant won't accept payments for the contract. 119 pay_deadline: Timestamp; 120 121 // Transfer deadline for the exchange. Must be in the 122 // deposit permissions of coins used to pay for this order. 123 wire_transfer_deadline: Timestamp; 124 125 // Merchant's public key used to sign this proposal; this information 126 // is typically added by the backend. Note that this can be an ephemeral key. 127 merchant_pub: EddsaPublicKey; 128 129 // Base URL of the (public!) merchant backend API. 130 // Must be an absolute URL that ends with a slash. 131 merchant_base_url: string; 132 133 // More info about the merchant (same as in v0). 134 merchant: Merchant; 135 136 // Human-readable description of the contract. 137 summary: string; 138 139 // Map from IETF BCP 47 language tags to localized summaries. 140 summary_i18n?: { [lang_tag: string]: string }; 141 142 // URL that will show that the order was successful after 143 // it has been paid for. Optional. When POSTing to the 144 // merchant, the placeholder "${ORDER_ID}" will be 145 // replaced with the actual order ID (useful if the 146 // order ID is generated server-side and needs to be 147 // in the URL). 148 // Note that this placeholder can only be used once. 149 // Either fulfillment_url or fulfillment_message must be specified. 150 fulfillment_url?: string; 151 152 // Message shown to the customer after paying for the order. 153 // Either fulfillment_url or fulfillment_message must be specified. 154 fulfillment_message?: string; 155 156 // Map from IETF BCP 47 language tags to localized fulfillment 157 // messages. 158 fulfillment_message_i18n?: { [lang_tag: string]: string }; 159 160 // List of products that are part of the purchase (see `Product`). 161 products: Product[]; 162 163 // After this deadline has passed, no refunds will be accepted. 164 refund_deadline: Timestamp; 165 166 // Specifies for how long the wallet should try to get an 167 // automatic refund for the purchase. If this field is 168 // present, the wallet should wait for a few seconds after 169 // the purchase and then automatically attempt to obtain 170 // a refund. The wallet should probe until "delay" 171 // after the payment was successful (i.e. via long polling 172 // or via explicit requests with exponential back-off). 173 // 174 // In particular, if the wallet is offline 175 // at that time, it MUST repeat the request until it gets 176 // one response from the merchant after the delay has expired. 177 // If the refund is granted, the wallet MUST automatically 178 // recover the payment. This is used in case a merchant 179 // knows that it might be unable to satisfy the contract and 180 // desires for the wallet to attempt to get the refund without any 181 // customer interaction. Note that it is NOT an error if the 182 // merchant does not grant a refund. 183 auto_refund?: RelativeTime; 184 185 // Delivery location for (all!) products (same as in v0). 186 delivery_location?: Location; 187 188 // Time indicating when the order should be delivered. 189 // May be overwritten by individual products. 190 delivery_date?: Timestamp; 191 192 // Nonce generated by the wallet and echoed by the merchant 193 // in this field when the proposal is generated. 194 // Note: required in contract, absent in order! 195 nonce: string; 196 197 // Array of possible specific contracts the wallet/customer 198 // may choose from by selecting the respective index when 199 // signing the deposit confirmation. 200 choices: DDContractChoice[]; 201 202 // Map from token family slugs to meta data about the 203 // respective token family. 204 token_families: { [token_family_slug: string]: ContractTokenFamily }; 205 206 // Extra data that is only interpreted by the merchant frontend. 207 // Useful when the merchant needs to store extra information on a 208 // contract without storing it separately in their database. 209 extra?: any; 210 211 // Exchanges that the merchant accepts for this currency. 212 exchanges: Exchange[]; 213 } 214 215 .. ts:def:: DDContractChoice 216 217 interface DDContractChoice { 218 // Price to be paid for this choice. Could be 0. 219 // The price is in addition to other instruments, 220 // such as rations and tokens. 221 // The exchange will subtract deposit fees from that amount 222 // before transferring it to the merchant. 223 amount: Amount; 224 225 // List of inputs the wallet must provision (all of them) to 226 // satisfy the conditions for the contract. 227 inputs: DDContractInput[]; 228 229 // List of outputs the merchant promises to yield (all of them) 230 // once the contract is paid. 231 outputs: DDContractOutput[]; 232 233 // Maximum total deposit fee accepted by the merchant for this contract. 234 max_fee: Amount; 235 } 236 237 .. ts:def:: DDContractInput 238 239 type DDContractInput = 240 | DDContractInputRation 241 | DDContractInputToken; 242 243 .. ts:def:: DDContractInputRation 244 245 interface DDContractInputRation { 246 type: "coin"; 247 248 // Price to be paid for the transaction. 249 price: Amount; 250 251 // FIXME-DOLD: do we want to move this into a 'details' 252 // sub-structure as done with tokens below? 253 class: "ration"; 254 255 // Base URL of the ration authority. 256 ration_authority_url: string; 257 }; 258 259 .. ts:def:: DDContractInputToken 260 261 interface DDContractInputToken { 262 type: "token"; 263 264 // Slug of the token family in the 265 // 'token_families' map on the order. 266 token_family_slug: string; 267 268 // Start of the validity period of the token. This is used to find the 269 // matching public key within the token family. 270 valid_after: Timestamp; 271 272 // Number of tokens of this type required. 273 // Defaults to one if the field is not provided. 274 number?: Integer; 275 }; 276 277 .. ts:def:: DDContractOutput 278 279 type DDContractOutput = 280 | DDContractOutputCoin 281 | DDContractOutputTaxReceipt 282 | DDContractOutputToken; 283 284 .. ts:def:: DDContractOutputCoin 285 286 interface DDContractOutputCoin { 287 type: "coins"; 288 289 // Amount of coins that will be yielded. 290 // This excludes any applicable withdraw fees. 291 brutto_yield: Amount; 292 293 // Base URL of the exchange that will issue the 294 // coins. 295 exchange_url: string; 296 }; 297 298 .. ts:def:: DDContractOutputTaxReceipt 299 300 interface DDContractOutputTaxReceipt { 301 type: "tax-receipt"; 302 303 // Base URL of the donation authority that will 304 // issue the tax receipt. 305 donau_url: string; 306 }; 307 308 .. ts:def:: DDContractOutputToken 309 310 interface DDContractOutputToken { 311 type: "token"; 312 313 // Slug of the token family in the 314 // 'token_families' map on the top-level. 315 token_family_slug: string; 316 317 // Start of the validity period of the token. This is used to find the 318 // matching public key within the token family. 319 valid_after: Timestamp; 320 321 // Number of tokens to be issued. 322 // Defaults to one if the field is not provided. 323 number?: Integer; 324 } 325 326 .. ts:def:: DDContractTokenDetails 327 328 type DDContractTokenDetails = 329 | DDContractSubscriptionTokenDetails 330 | DDContractDiscountTokenDetails 331 332 .. ts:def:: DDContractSubscriptionTokenDetails 333 334 interface DDContractSubscriptionTokenDetails { 335 class: "subscription"; 336 337 // Array of domain names where this subscription 338 // can be safely used (e.g. the issuer warrants that 339 // these sites will re-issue tokens of this type 340 // if the respective contract says so). May contain 341 // "*" for any domain or subdomain. 342 trusted_domains: string[]; 343 }; 344 345 .. ts:def:: DDContractDiscountTokenDetails 346 347 interface DDContractDiscountTokenDetails { 348 class: "discount"; 349 350 // Array of domain names where this discount token 351 // is intended to be used. May contain "*" for any 352 // domain or subdomain. Users should be warned about 353 // sites proposing to consume discount tokens of this 354 // type that are not in this list that the merchant 355 // is accepting a coupon from a competitor and thus 356 // may be attaching different semantics (like get 20% 357 // discount for my competitors 30% discount token). 358 expected_domains: string[]; 359 }; 360 361 .. ts:def:: DDContractTokenFamily 362 363 interface DDContractTokenFamily { 364 // Human-readable name of the token family. 365 name: string; 366 367 // Human-readable description of the semantics of 368 // this token family (for display). 369 description: string; 370 371 // Map from IETF BCP 47 language tags to localized descriptions. 372 description_i18n?: { [lang_tag: string]: string }; 373 374 // Public keys used to validate tokens issued by this token family. 375 keys: TokenIssuePublicKey[]; 376 377 // Class-specific information of the token 378 details: ContractTokenDetails; 379 380 // Must a wallet understand this token type to 381 // process contracts that consume or yield it? 382 critical: boolean; 383 384 // Number of tokens issued according to ASS authority 385 // FIXME: this is still rather speculative in the design... 386 ass?: Integer; 387 388 // Signature affirming sum of token issuance deposit (?) fees 389 // collected by an exchange according to the ASS authority. 390 // FIXME: this is still rather speculative in the design... 391 ass_cost?: Amount; 392 393 // Signature affirming the ass by the ASS authority. 394 // FIXME: this is still rather speculative in the design... 395 ass_sig?: EddsaSignature; 396 }; 397 398 .. ts:def:: DDTokenIssuePublicKey 399 400 type DDTokenIssuePublicKey = 401 | DDTokenIssueRsaPublicKey 402 | DDTokenIssueCsPublicKey; 403 404 .. ts:def:: DDTokenIssueRsaPublicKey 405 406 interface DDTokenIssueRsaPublicKey { 407 cipher: "RSA"; 408 409 // RSA public key. 410 rsa_pub: RsaPublicKey; 411 412 // Start time of this key's validity period. 413 valid_after: Timestamp; 414 415 // End time of this key's validity period. 416 valid_before: Timestamp; 417 } 418 419 .. ts:def:: DDTokenIssueCsPublicKey 420 421 interface DDTokenIssueCsPublicKey { 422 cipher: "CS"; 423 424 // CS public key. 425 cs_pub: Cs25519Point; 426 427 // Start time of this key's validity period. 428 valid_after: Timestamp; 429 430 // End time of this key's validity period. 431 valid_before: Timestamp; 432 } 433 434 435 Alternative Contracts 436 --------------------- 437 438 The contract terms object may contain any number of alternative contracts that 439 the user must choose between. The alternatives can differ by inputs, outputs 440 or other details. The wallet must filter the contracts by those that the user 441 can actually pay for, and move those that the user could currently not pay for 442 to the end of the rendered list. Similarly, the wallet must move up the 443 cheaper contracts, so if a contract has a definitively lower price and 444 consumes an available discount token, that contract should be moved up in the 445 list. 446 447 Which specific alternative contract was chosen by the user is indicated in the 448 ``choice_index`` field of the :ref:`TALER_DepositRequestPS <taler_depositrequestps>`. 449 450 451 Output Commitments 452 ------------------ 453 454 When a contract has outputs, the wallet must send an array of blinded tokens, 455 coins or tax receipts together with the payment request. The order in the 456 array must match the order in the outputs field of the contract. For currency 457 outputs, one array element must include all of the required planchets for a 458 batch withdrawal, but of course not the reserve signature. 459 460 .. note:: 461 462 We can probably spec this rather nicely if we first change the 463 batch-withdraw API to only use a single reserve signature. 464 465 This array of blinded values is hashed to create the output commitment hash 466 (``h_outputs``) in the :ref:`TALER_DepositRequestPS <taler_depositrequestps>`. 467 468 469 470 Subscriptions 471 ------------- 472 473 The user buys a subscription (and possibly at the same time an article) using 474 currency and the contract yields an additional subscription token as an 475 output. Active subscriptions are listed below the currencies in the wallet 476 under a new heading. Subscriptions are never auto-renewing, if the user wants 477 to extend the subscription they can trivially pay for it with one click. 478 479 When a contract consumes and yields exactly one subscription 480 token of the same type in a trusted domain, the wallet may automatically 481 approve the transaction without asking the user for confirmation (as it is free). 482 483 The token expiration for a subscription can be past the "end date" to enable a 484 previous subscription to be used to get a discount on renewing the 485 subscription. The wallet should show applicable contracts with a lower price 486 that only additionally consume subscription tokens after their end date before 487 higher-priced alternative offers. 488 489 Subscription tokens are "critical" in that a wallet implementation must 490 understand them before allowing a user to interact with this class of token. 491 Subscription token secrets should be derived from a master secret associated 492 with the subscription, so that the private keys are recoverable from backup. 493 To obtain the blind signatures, a merchant must offer an endpoint where 494 one can submit the public key of the N-1 subscription token and obtain the 495 blinded signature over the N-th subscription token. The wallet can then 496 effectively recover the subscription from backup using a binary search. 497 498 The merchant SPA should allow the administrator to create (maybe update) and 499 delete subscriptions. Each subscription is identified by a subscription 500 label and includes a validity period. 501 502 The merchant backend must then automatically manage (create, use, delete) the 503 respective signing keys. When creating an order, the frontend can just refer 504 to the subscription label (and possibly a start date) in the inputs or 505 outputs. The backend should then automatically substitute this with the 506 respective cryptographic fields for the respective time period and 507 subscription label. 508 509 510 511 512 Discounts 513 --------- 514 515 To offer a discount based on one or more previous purchases, a merchant must 516 yield some discount-specific token as an output with the previous purchase, 517 and then offer an alternative contract with a lower price that consumes currency 518 and the discount token. The wallet should show contracts with a lower price that 519 only additionally consume discount tokens 520 521 The merchant SPA should allow the administrator to create (maybe update) and 522 delete discount tokens. Each discount token is identified by a discount 523 label and includes an expiration time or validity duration. 524 525 The merchant backend must then automatically manage (create, use, delete) the 526 respective signing keys. When creating an order, the frontend can just refer 527 to the discount token label in the inputs or outputs. The backend should then 528 automatically substitute this with the respective cryptographic fields for the 529 respective discount token. 530 531 532 Donation Authority 533 ------------------ 534 535 A donation authority (DONAU) implements a service that is expected to be run 536 by a government authority that determines eligibility for tax deduction. A 537 DONAU blindly signs tax receipts using a protocol very close to that of the 538 Taler exchange's withdraw protocol, except that the reserves are not filled 539 via wire transfers but instead represent accounts of the organizations 540 eligible to issue tax deduction receipts. These accounts are basically 541 expected to have only negative balances, but the DONAU can set a negative 542 balance threshold per organization to limit the creation of tax deduction 543 receipts to a plausible amount. DONAU administrators are expected to be 544 able to add, update or remove these accounts using a SPA. Tax receipts are 545 blindly signed by keys that always have a usage period of one calendar year. 546 547 A stand-alone app for tax authorities can scan QR codes representing DONAU 548 signatures to validate that a given tax payer has donated a certain amount. 549 As RSA signatures are typically very large and a single donation may require 550 multiple blind signatures, CS blind signatures must also be supported. To 551 avoid encoding the public keys, QR codes with tax receipts should reference 552 the DONAU, the year and the amount, but not the specific public key. A 553 single donation may nevertheless be rendered using multiple QR codes. 554 555 Revocations, refresh, deposits, age-restrictions and other exchange features 556 are not applicable for a DONAU. 557 558 The merchant SPA should allow the administrator to manage DONAU accounts in 559 the merchant backend. Each DONAU account includes a base URL and a private 560 signing key for signing the requests to the DONAU on behalf of the eligible 561 organization. 562 563 When creating an order, the frontend must specify a configured DONAU base URL 564 in the outputs. The backend should then automatically interact with the DONAU 565 when the wallet supplies the payment request with the blinded tax receipts. 566 The DONAU interaction must only happen after the exchange confirmed that the 567 contract was successfully paid. A partial error must be returned if the 568 exchange interaction was successful but the DONAU interaction failed. In this 569 case, the fulfillment action should still be triggered, but the wallet should 570 display a warning that the donation receipt could not be obtained. The wallet 571 should then re-try the payment (in the background with an exponential 572 back-off) to possibly obtain the tax receipt at a later time. 573 574 575 Tax Receipts 576 ------------ 577 578 Tax receipts differ from coins and tokens in that what is blindly signed over 579 should be the taxpayer identification number of the tax payer. The format of 580 the taxpayer identification number should simply be a string, with the rest 581 being defined by the national authority. The DONAU should indicate in its 582 ``/config`` response what format this string should have, using possibly both 583 an Anastasis-style regex and an Anastasis-style function name (to check things 584 like checksums that cannot be validated using a regex). Wallets must then 585 validate the regex (if given) and if possible should implement the 586 Anastasis-style logic. 587 588 Wallets should collect tax receipts by year and offer an 589 export functionality. The export should generate either 590 591 (a) a JSON file, 592 (b) a PDF (with QR codes), or 593 (c) a series of screens with QR codes. 594 595 Wallets may only implement some of the above options due to resource 596 constraints. 597 598 The documents should encode the taxpayer ID, the amount and the DONAU 599 signature (including the year, excluding the exact public key as there should 600 only be one possible). 601 602 603 Rationing (future work) 604 ----------------------- 605 606 If per-capita rationing must be imposed on certain transactions, a rationing 607 authority (RA) must exist that identifies each eligible human and issues that 608 human a number of ration coins for the respective rationing period. An RA 609 largely functions like a regular exchange, except that eligible humans will 610 need to authenticate directly to withdraw rations (instead of transferring 611 fiat to an exchange). Merchants selling rationed goods will be (legally) 612 required to collect deposit confirmations in proportion to the amount of 613 rationed goods sold. A difference to regular exchanges is that RAs do not 614 charge any fees. RAs may or may not allow refreshing rations that are about 615 to expire for ration coins in the next period. 616 617 Once an RA is added to a wallet, it should automatically try to withdraw the 618 maximum amount of ration coins it is eligible for. Available rations should be 619 shown below the subscriptions by RA (if any). 620 621 ..note:: 622 623 RAs are considered an idea for future work and not part of our current timeline. 624 625 626 Limited Donations per Capita (future work) 627 ------------------------------------------ 628 629 If per-capita limitations must be imposed on anonymous donations (for example 630 for donations to political parties), an RA can be used to issue donation 631 rations that limit the amount of donations that can be made for the respective 632 period. 633 634 ..note:: 635 636 RAs are considered an idea for future work and not part of our current timeline. 637 638 639 640 Definition of Done 641 ================== 642 643 - Merchant backend support for multiple currencies 644 - Merchant backend support for consuming and issuing tokens 645 - Merchant SPA support for configuring new tokens of different types 646 - Wallet-core support for various new contract types 647 - Wallet-core filters for feasible contracts and possibly auto-executes subscriptions 648 - Wallet-GUIs (WebEx, Android, iOS) render new contract types 649 - Wallet-GUIs (WebEx, Android, iOS) allow user to select between multiple contracts 650 - Documentation for developers is up-to-date 651 - Token anonymity set size (ASS) authority implemented, documented 652 - Merchants report anonymity set size increases to ASS authority 653 - Wallets process anonymity set size reports from ASS authority 654 - Bachelor thesis written on applications and design 655 - Academic paper written on DONAU (requirements, design, implementation) 656 - DONAU implemented, documented 657 - DONAU receipt validation application implemented 658 - Integration tests exist in wallet-core 659 - Deliverables accepted by EC 660 661 While rationing is part of the design, we expect the actual implementation to 662 be done much later and thus should not consider it part of the "DONE" part. 663 Rationing is complex, especially as a refunded contract should probably also 664 refund the ration. 665 666 667 Alternatives 668 ============ 669 670 The first draft of this DD included the capability of paying with multiple 671 currencies for the same contract (for example, USD:1 and EUR:5) plus tokens 672 and rations. However, this is very complex, both for wallets (how to display), 673 for other merchant APIs (does the refund API have to become multi-currency as 674 well?) and there does not seem to be a good business case for it. So for now, 675 the price is always only in one currency. 676 677 678 Drawbacks 679 ========= 680 681 Significant change, but actually good ratio compared to use-cases covered. 682 683 684 Discussion / Q&A 685 ================ 686 687 (This should be filled in with results from discussions on mailing lists / personal communication.)