046-mumimo-contracts.rst (26908B)
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: Slug; 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?: WebURL; 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: WebURL; 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 // Because of that placeholder, the value given here is merely a 150 // string and not yet a `WebURL`; only after the substitution has 151 // been performed is the result a `WebURL`. 152 // Either fulfillment_url or fulfillment_message must be specified. 153 fulfillment_url?: string; 154 155 // Message shown to the customer after paying for the order. 156 // Either fulfillment_url or fulfillment_message must be specified. 157 fulfillment_message?: string; 158 159 // Map from IETF BCP 47 language tags to localized fulfillment 160 // messages. 161 fulfillment_message_i18n?: { [lang_tag: string]: string }; 162 163 // List of products that are part of the purchase (see `ProductSold`). 164 products: ProductSold[]; 165 166 // After this deadline has passed, no refunds will be accepted. 167 refund_deadline: Timestamp; 168 169 // Specifies for how long the wallet should try to get an 170 // automatic refund for the purchase. If this field is 171 // present, the wallet should wait for a few seconds after 172 // the purchase and then automatically attempt to obtain 173 // a refund. The wallet should probe until "delay" 174 // after the payment was successful (i.e. via long polling 175 // or via explicit requests with exponential back-off). 176 // 177 // In particular, if the wallet is offline 178 // at that time, it MUST repeat the request until it gets 179 // one response from the merchant after the delay has expired. 180 // If the refund is granted, the wallet MUST automatically 181 // recover the payment. This is used in case a merchant 182 // knows that it might be unable to satisfy the contract and 183 // desires for the wallet to attempt to get the refund without any 184 // customer interaction. Note that it is NOT an error if the 185 // merchant does not grant a refund. 186 auto_refund?: RelativeTime; 187 188 // Delivery location for (all!) products (same as in v0). 189 delivery_location?: Location; 190 191 // Time indicating when the order should be delivered. 192 // May be overwritten by individual products. 193 delivery_date?: Timestamp; 194 195 // Nonce generated by the wallet and echoed by the merchant 196 // in this field when the proposal is generated. 197 // Note: required in contract, absent in order! 198 nonce: string; 199 200 // Array of possible specific contracts the wallet/customer 201 // may choose from by selecting the respective index when 202 // signing the deposit confirmation. 203 choices: DDContractChoice[]; 204 205 // Map from token family slugs to meta data about the 206 // respective token family. 207 token_families: { [token_family_slug: Slug]: ContractTokenFamily }; 208 209 // Extra data that is only interpreted by the merchant frontend. 210 // Useful when the merchant needs to store extra information on a 211 // contract without storing it separately in their database. 212 extra?: any; 213 214 // Exchanges that the merchant accepts for this currency. 215 exchanges: Exchange[]; 216 } 217 218 .. ts:def:: DDContractChoice 219 220 interface DDContractChoice { 221 // Price to be paid for this choice. Could be 0. 222 // The price is in addition to other instruments, 223 // such as rations and tokens. 224 // The exchange will subtract deposit fees from that amount 225 // before transferring it to the merchant. 226 amount: Amount; 227 228 // List of inputs the wallet must provision (all of them) to 229 // satisfy the conditions for the contract. 230 inputs: DDContractInput[]; 231 232 // List of outputs the merchant promises to yield (all of them) 233 // once the contract is paid. 234 outputs: DDContractOutput[]; 235 236 // Maximum total deposit fee accepted by the merchant for this contract. 237 max_fee: Amount; 238 } 239 240 .. ts:def:: DDContractInput 241 242 type DDContractInput = 243 | DDContractInputRation 244 | DDContractInputToken; 245 246 .. ts:def:: DDContractInputRation 247 248 interface DDContractInputRation { 249 type: "coin"; 250 251 // Price to be paid for the transaction. 252 price: Amount; 253 254 // FIXME-DOLD: do we want to move this into a 'details' 255 // sub-structure as done with tokens below? 256 class: "ration"; 257 258 // Base URL of the ration authority. 259 ration_authority_url: WebURL; 260 }; 261 262 .. ts:def:: DDContractInputToken 263 264 interface DDContractInputToken { 265 type: "token"; 266 267 // Slug of the token family in the 268 // 'token_families' map on the order. 269 token_family_slug: Slug; 270 271 // Start of the validity period of the token. This is used to find the 272 // matching public key within the token family. 273 valid_after: Timestamp; 274 275 // Number of tokens of this type required. 276 // Defaults to one if the field is not provided. 277 number?: Integer; 278 }; 279 280 .. ts:def:: DDContractOutput 281 282 type DDContractOutput = 283 | DDContractOutputCoin 284 | DDContractOutputTaxReceipt 285 | DDContractOutputToken; 286 287 .. ts:def:: DDContractOutputCoin 288 289 interface DDContractOutputCoin { 290 type: "coins"; 291 292 // Amount of coins that will be yielded. 293 // This excludes any applicable withdraw fees. 294 brutto_yield: Amount; 295 296 // Base URL of the exchange that will issue the 297 // coins. 298 exchange_url: WebURL; 299 }; 300 301 .. ts:def:: DDContractOutputTaxReceipt 302 303 interface DDContractOutputTaxReceipt { 304 type: "tax-receipt"; 305 306 // Base URL of the donation authority that will 307 // issue the tax receipt. 308 donau_url: WebURL; 309 }; 310 311 .. ts:def:: DDContractOutputToken 312 313 interface DDContractOutputToken { 314 type: "token"; 315 316 // Slug of the token family in the 317 // 'token_families' map on the top-level. 318 token_family_slug: Slug; 319 320 // Start of the validity period of the token. This is used to find the 321 // matching public key within the token family. 322 valid_after: Timestamp; 323 324 // Number of tokens to be issued. 325 // Defaults to one if the field is not provided. 326 number?: Integer; 327 } 328 329 .. ts:def:: DDContractTokenDetails 330 331 type DDContractTokenDetails = 332 | DDContractSubscriptionTokenDetails 333 | DDContractDiscountTokenDetails 334 335 .. ts:def:: DDContractSubscriptionTokenDetails 336 337 interface DDContractSubscriptionTokenDetails { 338 class: "subscription"; 339 340 // Array of domain names where this subscription 341 // can be safely used (e.g. the issuer warrants that 342 // these sites will re-issue tokens of this type 343 // if the respective contract says so). May contain 344 // "*" for any domain or subdomain. 345 trusted_domains: string[]; 346 }; 347 348 .. ts:def:: DDContractDiscountTokenDetails 349 350 interface DDContractDiscountTokenDetails { 351 class: "discount"; 352 353 // Array of domain names where this discount token 354 // is intended to be used. May contain "*" for any 355 // domain or subdomain. Users should be warned about 356 // sites proposing to consume discount tokens of this 357 // type that are not in this list that the merchant 358 // is accepting a coupon from a competitor and thus 359 // may be attaching different semantics (like get 20% 360 // discount for my competitors 30% discount token). 361 expected_domains: string[]; 362 }; 363 364 .. ts:def:: DDContractTokenFamily 365 366 interface DDContractTokenFamily { 367 // Human-readable name of the token family. 368 name: string; 369 370 // Human-readable description of the semantics of 371 // this token family (for display). 372 description: string; 373 374 // Map from IETF BCP 47 language tags to localized descriptions. 375 description_i18n?: { [lang_tag: string]: string }; 376 377 // Public keys used to validate tokens issued by this token family. 378 keys: TokenIssuePublicKey[]; 379 380 // Class-specific information of the token 381 details: ContractTokenDetails; 382 383 // Must a wallet understand this token type to 384 // process contracts that consume or yield it? 385 critical: boolean; 386 387 // Number of tokens issued according to ASS authority 388 // FIXME: this is still rather speculative in the design... 389 ass?: Integer; 390 391 // Signature affirming sum of token issuance deposit (?) fees 392 // collected by an exchange according to the ASS authority. 393 // FIXME: this is still rather speculative in the design... 394 ass_cost?: Amount; 395 396 // Signature affirming the ass by the ASS authority. 397 // FIXME: this is still rather speculative in the design... 398 ass_sig?: EddsaSignature; 399 }; 400 401 .. ts:def:: DDTokenIssuePublicKey 402 403 type DDTokenIssuePublicKey = 404 | DDTokenIssueRsaPublicKey 405 | DDTokenIssueCsPublicKey; 406 407 .. ts:def:: DDTokenIssueRsaPublicKey 408 409 interface DDTokenIssueRsaPublicKey { 410 cipher: "RSA"; 411 412 // RSA public key. 413 rsa_pub: RsaPublicKey; 414 415 // Start time of this key's validity period. 416 valid_after: Timestamp; 417 418 // End time of this key's validity period. 419 valid_before: Timestamp; 420 } 421 422 .. ts:def:: DDTokenIssueCsPublicKey 423 424 interface DDTokenIssueCsPublicKey { 425 cipher: "CS"; 426 427 // CS public key. 428 cs_pub: Cs25519Point; 429 430 // Start time of this key's validity period. 431 valid_after: Timestamp; 432 433 // End time of this key's validity period. 434 valid_before: Timestamp; 435 } 436 437 438 Alternative Contracts 439 --------------------- 440 441 The contract terms object may contain any number of alternative contracts that 442 the user must choose between. The alternatives can differ by inputs, outputs 443 or other details. The wallet must filter the contracts by those that the user 444 can actually pay for, and move those that the user could currently not pay for 445 to the end of the rendered list. Similarly, the wallet must move up the 446 cheaper contracts, so if a contract has a definitively lower price and 447 consumes an available discount token, that contract should be moved up in the 448 list. 449 450 Which specific alternative contract was chosen by the user is indicated in the 451 ``choice_index`` field of the :ref:`TALER_DepositRequestPS <taler_depositrequestps>`. 452 453 454 Output Commitments 455 ------------------ 456 457 When a contract has outputs, the wallet must send an array of blinded tokens, 458 coins or tax receipts together with the payment request. The order in the 459 array must match the order in the outputs field of the contract. For currency 460 outputs, one array element must include all of the required planchets for a 461 batch withdrawal, but of course not the reserve signature. 462 463 .. note:: 464 465 We can probably spec this rather nicely if we first change the 466 batch-withdraw API to only use a single reserve signature. 467 468 This array of blinded values is hashed to create the output commitment hash 469 (``h_outputs``) in the :ref:`TALER_DepositRequestPS <taler_depositrequestps>`. 470 471 472 473 Subscriptions 474 ------------- 475 476 The user buys a subscription (and possibly at the same time an article) using 477 currency and the contract yields an additional subscription token as an 478 output. Active subscriptions are listed below the currencies in the wallet 479 under a new heading. Subscriptions are never auto-renewing, if the user wants 480 to extend the subscription they can trivially pay for it with one click. 481 482 When a contract consumes and yields exactly one subscription 483 token of the same type in a trusted domain, the wallet may automatically 484 approve the transaction without asking the user for confirmation (as it is free). 485 486 The token expiration for a subscription can be past the "end date" to enable a 487 previous subscription to be used to get a discount on renewing the 488 subscription. The wallet should show applicable contracts with a lower price 489 that only additionally consume subscription tokens after their end date before 490 higher-priced alternative offers. 491 492 Subscription tokens are "critical" in that a wallet implementation must 493 understand them before allowing a user to interact with this class of token. 494 Subscription token secrets should be derived from a master secret associated 495 with the subscription, so that the private keys are recoverable from backup. 496 To obtain the blind signatures, a merchant must offer an endpoint where 497 one can submit the public key of the N-1 subscription token and obtain the 498 blinded signature over the N-th subscription token. The wallet can then 499 effectively recover the subscription from backup using a binary search. 500 501 The merchant SPA should allow the administrator to create (maybe update) and 502 delete subscriptions. Each subscription is identified by a subscription 503 label and includes a validity period. 504 505 The merchant backend must then automatically manage (create, use, delete) the 506 respective signing keys. When creating an order, the frontend can just refer 507 to the subscription label (and possibly a start date) in the inputs or 508 outputs. The backend should then automatically substitute this with the 509 respective cryptographic fields for the respective time period and 510 subscription label. 511 512 513 514 515 Discounts 516 --------- 517 518 To offer a discount based on one or more previous purchases, a merchant must 519 yield some discount-specific token as an output with the previous purchase, 520 and then offer an alternative contract with a lower price that consumes currency 521 and the discount token. The wallet should show contracts with a lower price that 522 only additionally consume discount tokens 523 524 The merchant SPA should allow the administrator to create (maybe update) and 525 delete discount tokens. Each discount token is identified by a discount 526 label and includes an expiration time or validity duration. 527 528 The merchant backend must then automatically manage (create, use, delete) the 529 respective signing keys. When creating an order, the frontend can just refer 530 to the discount token label in the inputs or outputs. The backend should then 531 automatically substitute this with the respective cryptographic fields for the 532 respective discount token. 533 534 535 Donation Authority 536 ------------------ 537 538 A donation authority (DONAU) implements a service that is expected to be run 539 by a government authority that determines eligibility for tax deduction. A 540 DONAU blindly signs tax receipts using a protocol very close to that of the 541 Taler exchange's withdraw protocol, except that the reserves are not filled 542 via wire transfers but instead represent accounts of the organizations 543 eligible to issue tax deduction receipts. These accounts are basically 544 expected to have only negative balances, but the DONAU can set a negative 545 balance threshold per organization to limit the creation of tax deduction 546 receipts to a plausible amount. DONAU administrators are expected to be 547 able to add, update or remove these accounts using a SPA. Tax receipts are 548 blindly signed by keys that always have a usage period of one calendar year. 549 550 A stand-alone app for tax authorities can scan QR codes representing DONAU 551 signatures to validate that a given tax payer has donated a certain amount. 552 As RSA signatures are typically very large and a single donation may require 553 multiple blind signatures, CS blind signatures must also be supported. To 554 avoid encoding the public keys, QR codes with tax receipts should reference 555 the DONAU, the year and the amount, but not the specific public key. A 556 single donation may nevertheless be rendered using multiple QR codes. 557 558 Revocations, refresh, deposits, age-restrictions and other exchange features 559 are not applicable for a DONAU. 560 561 The merchant SPA should allow the administrator to manage DONAU accounts in 562 the merchant backend. Each DONAU account includes a base URL and a private 563 signing key for signing the requests to the DONAU on behalf of the eligible 564 organization. 565 566 When creating an order, the frontend must specify a configured DONAU base URL 567 in the outputs. The backend should then automatically interact with the DONAU 568 when the wallet supplies the payment request with the blinded tax receipts. 569 The DONAU interaction must only happen after the exchange confirmed that the 570 contract was successfully paid. A partial error must be returned if the 571 exchange interaction was successful but the DONAU interaction failed. In this 572 case, the fulfillment action should still be triggered, but the wallet should 573 display a warning that the donation receipt could not be obtained. The wallet 574 should then re-try the payment (in the background with an exponential 575 back-off) to possibly obtain the tax receipt at a later time. 576 577 578 Tax Receipts 579 ------------ 580 581 Tax receipts differ from coins and tokens in that what is blindly signed over 582 should be the taxpayer identification number of the tax payer. The format of 583 the taxpayer identification number should simply be a string, with the rest 584 being defined by the national authority. The DONAU should indicate in its 585 ``/config`` response what format this string should have, using possibly both 586 an Anastasis-style regex and an Anastasis-style function name (to check things 587 like checksums that cannot be validated using a regex). Wallets must then 588 validate the regex (if given) and if possible should implement the 589 Anastasis-style logic. 590 591 Wallets should collect tax receipts by year and offer an 592 export functionality. The export should generate either 593 594 (a) a JSON file, 595 (b) a PDF (with QR codes), or 596 (c) a series of screens with QR codes. 597 598 Wallets may only implement some of the above options due to resource 599 constraints. 600 601 The documents should encode the taxpayer ID, the amount and the DONAU 602 signature (including the year, excluding the exact public key as there should 603 only be one possible). 604 605 606 Rationing (future work) 607 ----------------------- 608 609 If per-capita rationing must be imposed on certain transactions, a rationing 610 authority (RA) must exist that identifies each eligible human and issues that 611 human a number of ration coins for the respective rationing period. An RA 612 largely functions like a regular exchange, except that eligible humans will 613 need to authenticate directly to withdraw rations (instead of transferring 614 fiat to an exchange). Merchants selling rationed goods will be (legally) 615 required to collect deposit confirmations in proportion to the amount of 616 rationed goods sold. A difference to regular exchanges is that RAs do not 617 charge any fees. RAs may or may not allow refreshing rations that are about 618 to expire for ration coins in the next period. 619 620 Once an RA is added to a wallet, it should automatically try to withdraw the 621 maximum amount of ration coins it is eligible for. Available rations should be 622 shown below the subscriptions by RA (if any). 623 624 ..note:: 625 626 RAs are considered an idea for future work and not part of our current timeline. 627 628 629 Limited Donations per Capita (future work) 630 ------------------------------------------ 631 632 If per-capita limitations must be imposed on anonymous donations (for example 633 for donations to political parties), an RA can be used to issue donation 634 rations that limit the amount of donations that can be made for the respective 635 period. 636 637 ..note:: 638 639 RAs are considered an idea for future work and not part of our current timeline. 640 641 642 643 Definition of Done 644 ================== 645 646 - Merchant backend support for multiple currencies 647 - Merchant backend support for consuming and issuing tokens 648 - Merchant SPA support for configuring new tokens of different types 649 - Wallet-core support for various new contract types 650 - Wallet-core filters for feasible contracts and possibly auto-executes subscriptions 651 - Wallet-GUIs (WebEx, Android, iOS) render new contract types 652 - Wallet-GUIs (WebEx, Android, iOS) allow user to select between multiple contracts 653 - Documentation for developers is up-to-date 654 - Token anonymity set size (ASS) authority implemented, documented 655 - Merchants report anonymity set size increases to ASS authority 656 - Wallets process anonymity set size reports from ASS authority 657 - Bachelor thesis written on applications and design 658 - Academic paper written on DONAU (requirements, design, implementation) 659 - DONAU implemented, documented 660 - DONAU receipt validation application implemented 661 - Integration tests exist in wallet-core 662 - Deliverables accepted by EC 663 664 While rationing is part of the design, we expect the actual implementation to 665 be done much later and thus should not consider it part of the "DONE" part. 666 Rationing is complex, especially as a refunded contract should probably also 667 refund the ration. 668 669 670 Alternatives 671 ============ 672 673 The first draft of this DD included the capability of paying with multiple 674 currencies for the same contract (for example, USD:1 and EUR:5) plus tokens 675 and rations. However, this is very complex, both for wallets (how to display), 676 for other merchant APIs (does the refund API have to become multi-currency as 677 well?) and there does not seem to be a good business case for it. So for now, 678 the price is always only in one currency. 679 680 681 Drawbacks 682 ========= 683 684 Significant change, but actually good ratio compared to use-cases covered. 685 686 687 Discussion / Q&A 688 ================ 689 690 (This should be filled in with results from discussions on mailing lists / personal communication.)