Skip to content

Commit

Permalink
Merge pull request #210 from cryptimeleon/feature/better-text
Browse files Browse the repository at this point in the history
Better text/descriptions
  • Loading branch information
JanBobolz authored Jun 20, 2023
2 parents 086aa4a + fd6f7be commit a4cc699
Show file tree
Hide file tree
Showing 16 changed files with 167 additions and 56 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -173,7 +173,7 @@ private fun DoubleSpendingText() {
private fun DoubleSpendingProtectionText(modifier: Modifier = Modifier) {
Column(modifier = modifier) {
Text(
"How does the Incentive-System protect against double-spending??",
"How does the Incentive-System protect against double-spending?",
style = MaterialTheme.typography.headlineMedium
)
Spacer(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -291,7 +291,7 @@ private fun TokenUpdateRow(
if (selectedUpdate != null) {
Text(selectedUpdate.description)
} else {
Text("Nothing")
Text("Nothing. Press to choose ❗")
}
}
Crossfade(targetState = expanded) { expanded ->
Expand All @@ -310,16 +310,17 @@ private fun TokenUpdateRow(
AnimatedVisibility(visible = expanded) {
Row(Modifier.horizontalScroll(scrollState)) {
tokenUpdates.forEachIndexed { i, it ->
RewardChoiceCard(
tokenUpdate = it,
selected = selectedUpdate == it,
onClick = { setSelectedTokenUpdate(it) },
modifier = Modifier
.width(200.dp)
.padding(8.dp)
.padding(start = if (i == 0) 16.dp else 0.dp)
.padding(end = if (i == tokenUpdates.lastIndex) 16.dp else 0.dp)
)
if (it.description != "Nothing" || tokenUpdates.size == 1) //removing the "Nothing" choice.
RewardChoiceCard(
tokenUpdate = it,
selected = selectedUpdate == it,
onClick = { setSelectedTokenUpdate(it) },
modifier = Modifier
.width(200.dp)
.padding(8.dp)
.padding(start = if (i == 0 || i == 1 && tokenUpdates[0].description == "Nothing") 16.dp else 0.dp)
.padding(end = if (i == tokenUpdates.lastIndex) 16.dp else 0.dp)
)
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,11 @@ private fun FinishedUiWithQRCode(message: String, paidBasketId: UUID, paidBasket
style = MaterialTheme.typography.headlineLarge,
fontWeight = FontWeight.SemiBold,
)
Text(
"Scan this QR code when leaving the store",
style = MaterialTheme.typography.bodyMedium,
fontWeight = FontWeight.SemiBold,
)
Spacer(modifier = Modifier.size(36.dp))
Surface(
shape = RoundedCornerShape(8.dp),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,14 +51,14 @@ val rewardsPage = Page(
)
val registrationPage = Page(
"Registration",
"During registration, we associate your name with a cryptographic credential. "
+ "This credential and thus your identity stays private, unless you try to attack the system.",
"During registration, we associate your name with a cryptographic credential. " +
"The name is public. However, your actions cannot be linked to your name (unless you explicitly try to double spend)",
"🙋",
isUserNamePage = true
)
val urlPage = Page(
"Custom Url",
"You can change the url of the incentive-system.",
"Custom Server",
"You can change the incentive-system server (only for advanced users).",
"📡",
isServerUrlPage = true
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ class OnboardingViewModel @Inject constructor(
get() = _serverUrl
val serverUrlValid = serverUrl.map { Patterns.WEB_URL.matcher(it).matches() }
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(5000), initialValue = true)
private val _name = MutableStateFlow("")
private val _name = MutableStateFlow("John Doe")
val name: StateFlow<String>
get() = _name

Expand All @@ -36,8 +36,8 @@ class OnboardingViewModel @Inject constructor(

fun storeData() {
runBlocking {
preferencesRepository.setUserData(name.value)
preferencesRepository.setServerUrl(if (serverUrl.value != "") serverUrl.value else BuildConfig.SERVER_URL)
preferencesRepository.setUserData(name.value.trim())
preferencesRepository.setServerUrl(if (serverUrl.value != "") serverUrl.value.trim() else BuildConfig.SERVER_URL)
}
}
}
2 changes: 1 addition & 1 deletion deployment/util.sh
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
#!/bin/bash

function generateSecret() {
export LC_CTYPE=C
export LC_ALL=C
tr -dc A-Za-z0-9 </dev/urandom | head -c 128
printf "\n"
}
Expand Down
3 changes: 3 additions & 0 deletions services/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,9 @@ subprojects {
}

apply plugin: "java"
compileJava {
options.release = 11
}

group = 'org.cryptimeleon.incentive'
}
Binary file added web/public/assets/is-additive-update.mp4
Binary file not shown.
Binary file added web/public/assets/is-general.mp4
Binary file not shown.
87 changes: 87 additions & 0 deletions web/src/components/AboutPage.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
<template>
<div class="prose prose-slate">
<h1>About Incentimeleon</h1>
<p>On this page, we explain how Incentimleon works and how it differs from typical implementations of incentive systems</p>

<h2>What is an incentive system and how does it usually work?</h2>
<p>
An incentive system (or customer loyalty system) is designed to reward customers for certain behavior. Usually, customers collect "points" for their purchases, and can later spend those points on rewards.
Typical examples are loyalty point systems in supermarkets or airline miles.
</p>
<video style="width:100%;
border:0;
-webkit-mask-image: -webkit-radial-gradient(white, black);
-webkit-backface-visibility: hidden;
-moz-backface-visibility: hidden;"
autoplay muted loop playsinline>
<source src="assets/is-general.mp4" type="video/mp4">
Your browser does not support the video tag.
</video>
<p>
Incentive systems in practice are very simple: to issue/redeem points, stores have an active database connection, customers present a card containing their database entry ID, which allows the incentive system provider to update the correct database entry.
</p>
<p>
Those systems come at a huge <strong>cost of privacy</strong>: while grocery shopping used to be a fully anonymous activity, presenting a unique ID enables the store/provider to associate otherwise harmless data ("<i>someone</i> just bought a teddy bear and tomatoes") to the user's identity ("<i>Jimothy</i> just bought a teddy bear and tomatoes; the same <i>Jimothy</i> who bought a pregnancy test yesterday").
</p>

<h2>How does Incentimeleon work?</h2>
Instead of storing the user's data (e.g., their point count) in a central database, <strong>Incentimeleon stores user data on the user's phone</strong> in the form of an authenticated token.
When the data needs to be updated (e.g., adding 7 points to the current point count), the provider <i>blindly</i> executes this update, without learning the user's identity or the old or the updated data.
<video style="width:100%;
border:0;
-webkit-mask-image: -webkit-radial-gradient(white, black);
-webkit-backface-visibility: hidden;
-moz-backface-visibility: hidden;"
autoplay muted loop playsinline>
<source src="assets/is-additive-update.mp4" type="video/mp4">
Your browser does not support the video tag.
</video>
This means that the provider or store never actually get to see the point counts or the user ID of a shopper, preventing the creation of user profiles in a strong cryptographic sense.


<h2>What are the challenges with this approach?</h2>
<p>
One of the main challenges is double-spending: When a user spends 700 points, how do we invalidate the user's old 1000 point token and force him to use his new 300 point token?
</p>
For this, Incentimeleon supports two mechanisms (in tandem):
<ul>
<li><strong>Online double-spending prevention</strong>: can detect double-spending before it happens, but requires persistent database connection.</li>
<li><strong>Offline double-spending detection</strong>: stores can speculatively accept tokens even when offline. In double-spending is detected later (e.g., when online again), the identity of the malicious user is revealed and losses can be retroactively recouped (e.g., through the legal system).</li>
</ul>


<h2>Why would anyone deploy Incentimeleon? Isn't collecting data the whole point?</h2>
<p>
Indeed, many digital incentive systems in practice are mainly motivated by data collection.
However, there are actually many incentive systems in operation that do not collect data at all. We all know that smaller stores often have analog stamp cards (buy 10 sandwiches, get one free), which simply reward loyalty, but clearly do not collect any private data.
Incentimeleon combines the privacy of the analog paper-based solution with the convenience and expressiveness of digital systems. It supports many different ways of rewarding customers apart from simple point collection (enabling gamification).
</p>

<p>
Since Incentimeleon demonstrates that a privacy-preserving solution for digital incentive systems is feasible, users and law makers can start demanding such a solution.
</p>

<h2>What's the bigger picture here?</h2>
<p>
There many other applications that can be phrased as "collect points and spend them".
For example, bus tickets can be bought in bulk ("collect 10 tickets") and then spent anonymously on the bus. Using Incentimeleon's techniques, one could even implement automatic fare capping in a way that does not require the bus provider to learn your movement patterns.
</p>
<p>
Furthermore, the more general idea of storing user data <i>with the user</i> and doing privacy-preserving updates on that data is a powerful idea to enable privacy in <i>many</i> contexts. Further cryptographic design work may be needed depending on the concrete application. Contact us with your idea!
</p>
<!-- Can replace database with data stored at user, can do updates. -->
<!-- Similar apps: buy bus tickets with prepaid card w/o revealing anything. -->

<h2>How was Incentimeleon developed?</h2>
Cryptimeleon is an <a href="https://github.com/cryptimeleon/incentive-system">open-source prototype</a> developed at Paderborn University as part of the SFB901 "<a href="https://sfb901.uni-paderborn.de/projects/project-area-t/subproject-t2">On-The-Fly Computing</a>".
If is largely based on the paper <a href="https://eprint.iacr.org/2020/382">Privacy-Preserving Incentive Systems with Highly Efficient Point-Collection</a>.
It has been developed using the <a href="https://cryptimeleon.org/">Cryptimeleon</a> cryptographic prototyping library.
</div>
</template>

<script setup>
</script>

<style scoped>
</style>
9 changes: 8 additions & 1 deletion web/src/components/IncHeader.vue
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
<nav class="text-slate-100 text-sm md:flex md:items-center md:justify-between px-4 md:px-8 md:container">
<div class="flex justify-between">
<router-link to="/" class="hidden md:block">
<p class="text-xl font-semibold py-4 text-white">Cryptimeleon Incentive System</p>
<p class="text-xl font-semibold py-4 text-white">Incentimeleon</p>
</router-link>
<router-link to="/" class="md:hidden">
<p class="text-xl font-semibold py-2 text-white">Incentive System</p>
Expand All @@ -29,6 +29,13 @@
</span>
</router-link>
</li>
<li>
<router-link to="/about">
<span class="text-white hover:text-gray-200">
About
</span>
</router-link>
</li>
<li>
<router-link to="/store-frontend">
<span class="text-white hover:text-gray-200">
Expand Down
37 changes: 14 additions & 23 deletions web/src/components/LandingPage.vue
Original file line number Diff line number Diff line change
@@ -1,30 +1,21 @@
<template>
<div class="prose prose-slate">
<h1>About This Project</h1>
<h1>The Incentimeleon system</h1>
<p>
This project page is still under construction!
<strong>Hey!</strong> This site is part of our prototype implementation of a privacy-preserving incentive system.
We use <strong>modern cryptographic methods</strong> (zero-knowledge proofs, pairing-based signatures, etc.) to reclaim <strong>user privacy</strong> when taking part in loyalty promotions.
</p>
<ul>
<li>
<a href="https://sfb901.uni-paderborn.de/">SFB901</a>
</li>
<li>
Open Source Prototype (<a
href="https://github.com/cryptimeleon/incentive-system">cryptimeleon/incentive-system</a>)
</li>
<li>
Powered by the <a href="https://cryptimeleon.org/">Cryptimeleon</a> cryptography prototyping library.
</li>
<li>
Based on the paper <a href=" https://eprint.iacr.org/2020/382">'Privacy-Preserving Incentive Systems
with Highly
Efficient
Point-Collection'</a> by Jan Bobolz, Fabian Eidens, Stephan Krenn, Daniel Slamanig, and Christoph
Striecks.
</li>
<li>
Developed at Paderborn University
</li>
<p>
This website, together with our app, allows you to explore and try out our solution.
</p>

<h1>
What's next?
</h1>
<ul> <!-- Ideally, this becomes a much more prominent collection of huge buttons to click -->
<li>🧑‍🏫 Learn: how does Incentimeleon work? [<router-link to="/about">📚 About page</router-link>]</li>
<li>🛒 Experience: what does the user see? [<a>📱 Play Store</a> / <a>📽️ Video</a>]</li>
<li>🧑‍💻 Check: what does the provider see? [<router-link to="/store-frontend">🏪 Store view</router-link> / <router-link to="provider-frontend">🌍 Provider view</router-link>]</li>
</ul>
</div>
</template>
Expand Down
9 changes: 8 additions & 1 deletion web/src/components/ProviderRegistrationCoupons.vue
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,14 @@
<ServiceStatus :loading="loading" :online="online"/>
</div>
<div class="prose text-lg pb-2">
Some provider text here.
The provider is a cloud entity that operates the incentive system.
It issues tokens to users, detects cheating (double-spending) users,
and it logs all operations done by each store (for the sake of clearing, i.e. settling debt incurred by a store from granting rewards to users).
</div>
<div class="prose text-lg pb-2">
The provider keeps a list of all registered users for the sake of identifying double-spending users:
cryptographic guarantees ensure that the provider can retrieve a double-spending user's public key; then the provider can use that to point to the right user entry.
However, for honest users, who do not double-spend, none of their actions with the stores can be traced back to their public key and the only information the provider has is that they are in the system (but cannot link this information to purchases).
</div>
<div class="text-2xl font-bold">Registration Coupons</div>
<div class="grid grid-cols-1 md:grid-cols-2 gap-4 py-4">
Expand Down
18 changes: 10 additions & 8 deletions web/src/components/store/BasketCard.vue
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
<template>
<div class="w-full rounded overflow-hidden shadow-md" :class="hasDS ? 'bg-red-200' : 'bg-white'">
<div class="px-6 py-4 w-full">
<div class="font-bold text-lg mb-2">
{{ basket.basketID }}
<!-- {{ basket }} -->
<div class="text-sm mb-2">
Transaction ID: {{ basket.basketID }}
</div>
<div class="text-gray-700 text-base grid md:grid-cols-2 grid-cols-1 gap-4">
<div class="flex-none md:basis-1/2">
<div class="font-bold">
Contents
🛒 Bought items
</div>
<div v-for="item in basket.basketItems" :key="item.name">
<div class="flex flex-row space-x-2 justify-between">
Expand Down Expand Up @@ -40,7 +41,7 @@
<div class="flex-none grow-0 md:basis-1/2">
<div>
<div class="font-bold">
Rewards
🎁 Reward items
</div>
<div v-if="basket.rewardItems.length > 0">
<div v-for="reward in basket.rewardItems" :key="reward.id">
Expand All @@ -50,14 +51,15 @@
<div v-else>
No rewards
</div>
<div v-if="hasDS">
<div>
<div class="font-bold">
DoubleSpending
💾 Customer data
</div>
<div v-if="hasDS">User has illegally double-spent.</div>
<div>
User: {{ basket.dsData.userInfo }}
{{ hasDS ? basket.dsData.userInfo : "No information"}}
</div>
<p class="truncate max-w-full">
<p v-if="hasDS" class="truncate max-w-full">
Secret Key: {{ basket.dsData.userSecretExponent.split("INT:")[1] }}
</p>
</div>
Expand Down
5 changes: 4 additions & 1 deletion web/src/components/store/StoreMain.vue
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,10 @@
<ServiceStatus :loading="loading" :online="online"/>
</div>
<div class="prose text-lg">{{ description }}</div>
<div class="text-2xl font-bold pt-2">Baskets</div>
<div class="prose text-lg">Below, you can see the data this store holds,
namely what products are being bought and what rewards are being chosen.
The store does not learn whom each basket belongs to, nor any details about the user data (e.g., how many points they have).</div>
<div class="text-2xl font-bold pt-2">Transactions in Store</div>
<BasketList :baskets="basketWithDsData"/>
</div>
</template>
Expand Down
9 changes: 7 additions & 2 deletions web/src/router/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import {createRouter, createWebHashHistory} from 'vue-router';

// Lazy-load routes
const LandingPage = () => import("@/components/LandingPage.vue")
const AboutPage = () => import("@/components/AboutPage.vue")
const PrivacyPolicy = () => import("@/components/PrivacyPolicy.vue")
const ImpressumPage = () => import("@/components/ImpressumPage.vue")
const StoreMain = () => import("@/components/store/StoreMain.vue")
Expand All @@ -13,6 +14,10 @@ const routes = [
path: '/',
component: LandingPage
},
{
path: '/about',
component: AboutPage
},
{
path: '/privacy-policy',
component: PrivacyPolicy
Expand All @@ -27,7 +32,7 @@ const routes = [
props: {
baseUrl: "store",
name: "Store One",
description: "Just a normal store."
description: "Just a normal store participating in the incentive system."
}
},
{
Expand All @@ -36,7 +41,7 @@ const routes = [
props: {
baseUrl: "store-two",
name: "Store Two",
description: "Another normal store."
description: "Another store. Because there is no persistent internet connection between Store One and Store Two, you can spend the same token at both without them immediately noticing (it will, however, be noticed by the provider, who will be able to de-anonymize double-spending users)."
}
},
{
Expand Down

0 comments on commit a4cc699

Please sign in to comment.