Skip to content

Commit

Permalink
Merge remote-tracking branch 'origin/main'
Browse files Browse the repository at this point in the history
  • Loading branch information
ineiti committed Oct 31, 2024
2 parents 7c8c16e + d98cba0 commit 509767c
Show file tree
Hide file tree
Showing 4 changed files with 59 additions and 46 deletions.
8 changes: 8 additions & 0 deletions LICENSE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
Copyright 2024 EPFL


Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
6 changes: 6 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,12 @@ PATH=$PATH:node_modules/.bin jupyter-lab
## Alternatively, use Devbox

We support installation using [Devbox](https://www.jetify.com/devbox/docs/quickstart/) which facilitates environment management.
To install devbox, run the following command:

```bash
curl -fsSL https://get.jetify.com/devbox | bash
```

Once devbox is install, you can run the following command to launch jupyter-lab:

```bash
Expand Down
63 changes: 32 additions & 31 deletions exercise-1.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@
"\n",
"# Exercise 1 - Signing Simply with RSA\n",
"\n",
"This first exercise shows how to prove the validity of a credential using an RSA signature.\n",
"Then we create a simple version of Selective Disclosure (SD) to hide some of the data.\n",
"This first exercise shows how to prove the validity of a credential using an RSA signature. \n",
"Then we create a simple version of Selective Disclosure (SD) to hide some of the data. \n",
"Finally we'll fix our errors in the simple SD implementation.\n",
"\n",
"To understand these concepts in more detail, please refer to our blog post on [E-ID infrastructure](https://c4dt.epfl.ch/article/the-swiss-confederation-e-id-public-sandbox-trust-infrastructure-part-2/)\n",
Expand All @@ -35,13 +35,13 @@
"In this first section you'll learn how to do a simple protection of a credentials using signing.\n",
"You'll find the following elements:\n",
"\n",
"- credential: an object holding personal data\n",
"- issuer: a trusted entity who can sign a credential\n",
"- holder: the person described by the personal data\n",
"- verifier: wanting to learn parts of the personal data of the holder\n",
"- **credential**: an object holding personal data\n",
"- **issuer**: a trusted entity who can sign a credential\n",
"- **holder**: the person described by the personal data\n",
"- **verifier**: wanting to learn parts of the personal data of the holder\n",
"\n",
"### Definition: Verifiable Credentials\n",
"A verifiable credential, in its simplest form, is a signed string of data. An issuer will issue a credential by signing a specific string of data then sharing that string of data along with a cryptographic signature that can prove that this string was authorized/ issued by this specific issuer."
"A verifiable credential, in its simplest form, exists as a signed string of data. An issuer will issue a credential by signing a specific string of data then sharing that string of data along with a cryptographic signature that can prove that this string was authorized/ issued by this specific issuer."
]
},
{
Expand All @@ -52,10 +52,10 @@
"outputs": [],
"source": [
"// We start by creating a typical E-ID credential object that we will use through out this exercise\n",
"const date = new Date(\"1993-08-01T00:00:00\")\n",
"const birthDate = new Date(\"1993-08-01T00:00:00\")\n",
"const ID_DATA = {\n",
" name: \"Jack Sparrow\",\n",
" timeOfBirth: date.getTime(),\n",
" timeOfBirth: birthDate.getTime(),\n",
" profession: \"IT Manager\"\n",
"}"
]
Expand Down Expand Up @@ -105,7 +105,7 @@
"const signature = signer.sign(privateKey, 'base64');\n",
"\n",
"console.log(\"The signed message is:\", message);\n",
"console.log(\"The signature is:\", signature);"
"console.log(\"\\n The signature is:\", signature);"
]
},
{
Expand All @@ -131,9 +131,9 @@
"metadata": {},
"outputs": [],
"source": [
"// Teh verifier recieves the \"message\" and the \"signature\".\n",
"// The verifier recieves the \"message\" and the \"signature\".\n",
"// We suppose it has a copy of the issuer's public key using some kind of\n",
"// Poublic Key Infrastructure (PKI).\n",
"// Public Key Infrastructure (PKI).\n",
"\n",
"let verifier = crypto.createVerify('SHA256');\n",
"verifier.update(message)\n",
Expand Down Expand Up @@ -165,7 +165,14 @@
"What if the holder of the credential wants to only share his name and profession but not his timeOfBirth?\n",
"The current implementation wouldn't allow for that, so we will need to change it.\n",
"The simplest solution is to hash all fields, and then only send the fields to be disclosed to the verifier.\n",
"\n",
"\n"
]
},
{
"cell_type": "markdown",
"id": "027f0b3f-23e7-4d46-ad11-6d41ac3bb668",
"metadata": {},
"source": [
"### Issuer"
]
},
Expand Down Expand Up @@ -251,7 +258,7 @@
"\n",
"### Verifier\n",
"\n",
"The verifier now wants to make sure that the data they got from the holder are correct."
"The verifier now wants to make sure that the data they got from the holder is correct."
]
},
{
Expand All @@ -261,12 +268,12 @@
"metadata": {},
"outputs": [],
"source": [
"// First the verifier has to check that the signature on the hashes is correct:\n",
"// First, the verifier has to check that the signature on the hashes is correct:\n",
"let verifier = crypto.createVerify('SHA256');\n",
"verifier.update(message)\n",
"console.log(\"Signature verification:\", verifier.verify(publicKey, signature, 'base64'))\n",
"\n",
"// Now the verifier can compare the disclosed data with the hashed values in the credential.\n",
"// Now, the verifier can compare the disclosed data with the hashed values in the credential.\n",
"// If they are equal, and the hash-function is cryptographically secure, the verifier can be covinced that the data is correct.\n",
"const RETRIEVED_DATA = JSON.parse(message);\n",
"for (const [key, value] of Object.entries(HOLDER_DISCLOSED_DATA)){\n",
Expand All @@ -276,7 +283,7 @@
" }\n",
"}\n",
"\n",
"// Since we've already verified that the hashed message is valid in the previous code cell\n",
"// Since we've already verified that the hashed message is valid in the previous code cell,\n",
"// and now we verified that the hashed values are equal to the revealed values, then\n",
"// we conclude that we trust these revealed data.\n",
"console.log(\"Hashed values are equal, so the following is verified:\", HOLDER_DISCLOSED_DATA);"
Expand All @@ -289,31 +296,33 @@
"source": [
"### Challenges\n",
"\n",
"1. Print the hashes of `hashValue(value)` and from the `RETRIEVED_DATA(key)` and compare them visually\n",
"1. Print the hashes using `hashValue(value)` and compare each output to `RETRIEVED_DATA(key)` and compare them visually\n",
"2. Change the disclosed fields and make sure it still runs"
]
},
{
"cell_type": "markdown",
"id": "f37642f1-e391-43e3-8646-42fccfb0cc7b",
"metadata": {},
"metadata": {
"jp-MarkdownHeadingCollapsed": true
},
"source": [
"---\n",
"\n",
"## 3. Discussion: security of this scheme, and introduction to unlinkability\n",
"\n",
"### Security of hashed values\n",
"\n",
"To keep some anonymity, the fields which the holder decides not to disclose remain hashed.\n",
"To keep some anonymity, the fields which the holder decides not to disclose remain shared with the verifier in a hashed format.\n",
"How secure is this?\n",
"For example, if the holder selectively discloses the `profession`, what can the verifier do with the other fields?\n",
"\n",
"### Unlinkability\n",
"\n",
"One of the big problems in current day ads is that even if you visit different websites, the ad-industry will correlate these visits into a single user profile.\n",
"One of the big problems in current day ads is that even if you visit different websites, the advertising industry will correlate these visits into a single user profile.\n",
"This allows these data brokers to sell your profile not only for ads, but also for influence campains, and for geo-tracking.\n",
"Not only ad companies can do this, but these profiles are sold by the data brokers also to the government, or even to private persons!\n",
"For this reason, presenting a credential multiple times should be **unlinkable**.\n",
"Not only ad companies can do this, but these profiles are also sold by the data brokers to the government, or even to private persons!\n",
"For this reason, multiple presentations of a credential should be **unlinkable**.\n",
"\n",
"Does the current scheme guarantee unlinkability of the holder towards different verifiers?"
]
Expand All @@ -333,14 +342,6 @@
"2. How would you hack the `name`, or `profession`?\n",
"3. Reimplement the communication between the holder and verifier modifying the hash function in a way that doesn't make it easy to guess the fields"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "052d9294-9263-42d7-9075-9ab231fbffa8",
"metadata": {},
"outputs": [],
"source": []
}
],
"metadata": {
Expand Down
28 changes: 13 additions & 15 deletions exercise-3.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,9 @@
"# Exercise 3 - Predicate proofs with ZKPs\n",
"\n",
"Now that we can do a privacy-preserving unlinkable selective disclosure, we can tackle the next step:\n",
"removing even more information by only proving the actually relevant information.\n",
"For an age check, the verifier doesn't need to know our birthdate.\n",
"It's enough if we can convince them that we are above, below, or in the range of a certain age.\n",
"removing even more information by only proving the minimally required information.\n",
"For an age check, the verifier doesn't need to know our exact birthdate; \n",
"it's enough to prove that we are above, below, or in the range of a certain age.\n",
"\n",
"## Sections\n",
"\n",
Expand Down Expand Up @@ -129,9 +129,9 @@
"source": [
"### Verifier\n",
"\n",
"We suppose that the holder takes contact with a verifier to get a service from it.\n",
"As a first step, the verifier must perform a trusted setup.\n",
"It consists of the following parts:\n",
"We suppose that the holder gets in contact with a verifier to get a service from it. \n",
"As a first step, the verifier must perform a trusted setup. \n",
"It consists of the following parts: \n",
"\n",
"- a proving key, used to create the proof, and sent to the holder\n",
"- a verifying key, used to verify the proof"
Expand All @@ -144,8 +144,8 @@
"metadata": {},
"outputs": [],
"source": [
"// The verifier is responsible for creating these keys, then sharing only the proving key with \n",
"// the credential holder.\n",
"// The verifier is responsible for creating these keys, \n",
"// then sharing only the proving key with the credential holder.\n",
"import { BoundCheckSnarkSetup, SetupParam } from '@docknetwork/crypto-wasm-ts';\n",
"const provingKey = BoundCheckSnarkSetup();\n",
"const snarkProvingKey = provingKey.decompress();\n",
Expand All @@ -159,7 +159,7 @@
"source": [
"### Credential Holder\n",
"\n",
"With the proving key, the holder can now create a proof.\n",
"With the proving key, the holder can now create a proof. \n",
"In our case, the holder reveals two attributes and creates a range proof to prove that: `170 <= height < 190`."
]
},
Expand All @@ -184,7 +184,7 @@
"builder.enforceBounds(0, 'credentialSubject.height', 170, 190, 'heightRangeCheck', snarkProvingKey);\n",
"const presentation = builder.finalize();\n",
"\n",
"// This is a serialized version, to be sent across an API to the verifier.\n",
"// This is a serialized version, to be sent through an API to the verifier.\n",
"const lgProofForVerifier = presentation.toJSON();\n",
"console.log(\"Data sent to verifier:\", lgProofForVerifier);"
]
Expand Down Expand Up @@ -224,7 +224,7 @@
"source": [
"import { Presentation } from '@docknetwork/crypto-wasm-ts'\n",
"\n",
"// Now the verifier can check whether the proof is valid.\n",
"// Now, the verifier can check if the proof is valid.\n",
"const predicateParams = new Map([['heightRangeCheck', snarkVerifyingKey]]);\n",
"const recreatedPres = Presentation.fromJSON(lgProofForVerifier)\n",
"console.log(\"Credential schema and revealed attributes:\", lgProofForVerifier[\"spec\"][\"credentials\"][0]);\n",
Expand All @@ -234,13 +234,11 @@
{
"cell_type": "markdown",
"id": "fde7cff9-44ab-4096-843f-16f3eacfa2c0",
"metadata": {
"jp-MarkdownHeadingCollapsed": true
},
"metadata": {},
"source": [
"### Challenges\n",
"\n",
"1. What happens if you try to create a proof which is not satisfied by the credential? Why?\n",
"1. What happens if you try to create a proof with a predicate which doesn't apply to the credential? Why?\n",
"2. How does the verifier know the bounds check performed? Does it need this information? Why (not)?\n",
"3. Change the proof to be on a different field of the credential\n",
"4. Add a second range proof"
Expand Down

0 comments on commit 509767c

Please sign in to comment.