Compare commits

...

30 Commits

Author SHA1 Message Date
mfahampshire 20e8d0db0b first pass changing ecash/coconut to zknym for informative nym-cli commands 2024-09-05 11:09:24 +02:00
mfahampshire 6791fab21d changed info! notice re: terminology 2024-09-05 11:02:24 +02:00
mfahampshire 490ae434b4 added zknym diagrams to images 2024-09-04 14:59:09 +02:00
mfahampshire fe91a65166 added diagrams 2024-09-04 14:58:53 +02:00
mfahampshire 5946d51e5b removed comment 2024-09-04 14:58:31 +02:00
mfahampshire 6f1f14befe tweaked archive explainer 2024-09-04 14:57:30 +02:00
mfahampshire 567c928cde rename dir from ecash to zknym 2024-09-03 15:37:37 +02:00
mfahampshire b8e2503fdd vocabulary change over all ecash docs 2024-09-03 15:35:11 +02:00
mfahampshire 4d26d683e0 small streamlining 2024-09-03 12:45:42 +02:00
mfahampshire b04dc55aba added archive warning 2024-09-03 12:45:26 +02:00
Jaya Klara Brekke bca0fc2694 Update double-spend-prot.md (#4830) 2024-09-03 09:31:16 +00:00
Jaya Klara Brekke d97d839f35 Update zknym-overview.md (#4829) 2024-09-03 09:31:01 +00:00
Jaya Klara Brekke 4bdbe7710c Update what-are-zknyms.md (#4828) 2024-09-03 09:28:07 +00:00
mfahampshire 589ee64516 refresh older imported text from archive 2024-08-30 09:33:53 +02:00
mfahampshire b20ab5dc50 tweak 2024-08-30 09:16:11 +02:00
mfahampshire 5bdff28a11 tweaked overall content 2024-08-29 18:02:52 +02:00
mfahampshire 4795a643a4 added more info from archive page 2024-08-29 18:02:38 +02:00
mfahampshire f7f6421415 first pass double spend doc 2024-08-29 18:02:22 +02:00
mfahampshire 891cfb80ea small tweak to archive coconut page 2024-08-29 18:02:06 +02:00
mfahampshire 9344296804 remove double spend stub from overview doc 2024-08-28 17:35:29 +02:00
mfahampshire 3538b5237e split out features into own pages 2024-08-28 17:33:33 +02:00
mfahampshire 5581f735d2 removed feature info from main overview doc 2024-08-28 17:33:19 +02:00
mfahampshire c0ede6a506 new structure 2024-08-28 17:33:04 +02:00
mfahampshire 5d6b84a94f added todo 2024-08-23 12:46:31 +02:00
mfahampshire 66fff0edf0 simplified subheading for zknyms 2024-08-23 12:16:37 +02:00
mfahampshire 2bdb623101 added high level examples to zknym overview page 2024-08-23 12:16:03 +02:00
mfahampshire 1f435880d7 restructure + reword + skeleton of incremental spend 2024-08-22 15:42:44 +02:00
mfahampshire 34579222c5 removed unnecessary file for moment 2024-08-22 15:42:23 +02:00
mfahampshire 2a43134327 made generic 2024-08-21 14:47:18 +02:00
mfahampshire 844bcba6e8 first pass ecash docs 2024-08-21 14:20:26 +02:00
19 changed files with 292 additions and 48 deletions
-22
View File
@@ -1,22 +0,0 @@
// Copyright 2022 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use clap::{Args, Subcommand};
pub mod import_ticket_book;
pub mod issue_ticket_book;
pub mod recover_ticket_book;
#[derive(Debug, Args)]
#[clap(args_conflicts_with_subcommands = true, subcommand_required = true)]
pub struct Ecash {
#[clap(subcommand)]
pub command: EcashCommands,
}
#[derive(Debug, Subcommand)]
pub enum EcashCommands {
IssueTicketBook(issue_ticket_book::Args),
RecoverTicketBook(recover_ticket_book::Args),
ImportTicketBook(import_ticket_book::Args),
}
+1 -1
View File
@@ -1,7 +1,7 @@
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
pub mod coconut;
pub mod context;
pub mod utils;
pub mod validator;
pub mod zknym;
+22
View File
@@ -0,0 +1,22 @@
// Copyright 2022 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use clap::{Args, Subcommand};
pub mod import_credits;
pub mod issue_credits;
pub mod recover_credits;
#[derive(Debug, Args)]
#[clap(args_conflicts_with_subcommands = true, subcommand_required = true)]
pub struct Zknym {
#[clap(subcommand)]
pub command: ZknymCommands,
}
#[derive(Debug, Subcommand)]
pub enum ZknymCommands {
IssueCredits(issue_credits::Args),
RecoverCredits(recover_credits::Args),
ImportCredits(import_credits::Args),
}
+9 -3
View File
@@ -31,9 +31,15 @@
- [RPC Nodes](nyx/rpc-node.md)
- [Ledger Live Support](nyx/ledger-live.md)
# Coconut
- [Coconut](coconut.md)
- [Bandwidth Credentials](bandwidth-credentials.md)
# zkNyms (prev. Coconut)
- [What are zk-nyms?](zknym/what-are-zknyms.md)
- [zk-nym Generation & Useage: Overview](zknym/zknym-overview.md)
- [Feature: Unlinkability](zknym/unlinkability.md)
- [Feature: Double Spend Protection](zknym/double-spend-prot.md)
- [Feature: Rerandomisation & Incremental Spend](zknym/rerandomise.md)
- [Archive](zknym/archive.md)
- [Coconut](zknym/coconut.md)
- [Bandwidth Credentials](zknym/bandwidth-credentials.md)
# Tools
- [NymCLI](tools/nym-cli.md)
Binary file not shown.

After

Width:  |  Height:  |  Size: 301 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 283 KiB

+3
View File
@@ -0,0 +1,3 @@
# Archive
You can find the previously published Coconut scheme pages in this archive. This has since been superceded by the zk-nyms scheme, which combines elements of the [Coconut Credential](./coconut.md) and [Offline Ecash](https://arxiv.org/pdf/2303.08221) schemes.
@@ -1,8 +1,13 @@
# Bandwidth Credentials
```admonish caution
This page is now archived.
For up-to-date example interaction with zk-nyms navigate to the [zk-nym unlinkability](./unlinkability.md) page.
```
You can now try using Nym Bandwidth Credentials in our [Sandbox testnet environment](https://sandbox-explorer.nymtech.net).
Create a `sandbox.env` file with the following details:
Create a `sandbox.env` file with the following details:
```
CONFIGURED=true
@@ -32,17 +37,17 @@ NYXD="https://rpc.sandbox.nymtech.net"
NYM_API="https://sandbox-validator1-api.nymtech.net/api"
```
Create an account on Sandbox using the nym-cli:
Create an account on Sandbox using the nym-cli:
```./nym-cli --config-env-file <path-to>sandbox.env account create```
You will need `nymt` funds sent to this account. Get in touch via Nym [Telegram](https://t.me/nymchan) or [Discord](https://nymtech.net/go/discord) and we can send them to you.
You will need `nymt` funds sent to this account. Get in touch via Nym [Telegram](https://t.me/nymchan) or [Discord](https://nymtech.net/go/discord) and we can send them to you.
Next, you init the nym-client with the enabled credentials mode set to true:
Next, you init the nym-client with the enabled credentials mode set to true:
```./nym-client --config-env-file <path-to>sandbox.env init --id <ID> --enabled-credentials-mode true```
Using the new credentials binary, purchase some credentials for the client. The recovery directory is a directory where the credentials will be temporarily stored in case the request fails.
Using the new credentials binary, purchase some credentials for the client. The recovery directory is a directory where the credentials will be temporarily stored in case the request fails.
```./credential --config-env-file <path-to>sandbox.env run --client-home-directory <path-to-the-client-config> --nyxd-url https://rpc.sandbox.nymtech.net --mnemonic "<mnemonic of the account created above>" --amount 50 --recovery-dir <a-path> ```
@@ -56,11 +61,11 @@ Run the network requester which can be downloaded [here](https://github.com/nymt
> You need to run this version for now, as the `nym-client` functionality was recently integrated into the `network-requester` binary but for the moment cannot support coconut credentials natively.
Now time to init the socks5 client:
Now time to init the socks5 client:
`./nym-socks5-client --config-env-file <path-to>sandbox.env init --id <ID> --provider <insert provider address which was returned when init-ing the nym-client> --enabled-credentials-mode true`
Purchase credentials for this now too:
Purchase credentials for this now too:
`./credential --config-env-file <path-to>sandbox.env run --client-home-directory <path-to-socks5-config> --nyxd-url https://rpc.sandbox.nymtech.net --mnemonic "<any valid sandbox mnemonic>" --amount 100 --recovery-dir <a-path>`
@@ -68,13 +73,13 @@ Run the socks5 client:
`./nym-socks5-client --config-env-file <path-to>sandbox.env run --id <ID> --enabled-credentials-mode true`
NOTE
NOTE
You can check to see if credentials have been correctly purchased by installing sqlite, and proceeding to do the following:
```
sqlite3 ~/.nym/socks5-clients/<ID>/data/credentials_database.db
sqlite3 ~/.nym/socks5-clients/<ID>/data/credentials_database.db
select * from coconut_credentials;
```
Keep in mind 1GB = 1NYM
Keep in mind 1GB = 1NYM
@@ -1,6 +1,10 @@
# Coconut
> Coconut is in active development - stay tuned for code and integration examples
```admonish caution
This page is now archived: the current anonymous credential scheme - zk-nyms - is partially based on Coconut, but this page is really just retained for posterity.
For up-to-date information on anonymous mixnet access, navigate to the [zk-nym overview](./what-are-zknyms.md).
```
Coconut is a cryptographic signature scheme that produces privacy-enhanced credentials. It lets application programmers who are concerned with resource access control to think and code in a new way.
@@ -0,0 +1,39 @@
# Double Spend Protection
Double spend protection in the context of zk-nym is a balancing act between speed, reliability, and UX. There are two possible modes for protecting against attempted double spending of zk-nyms:
- Online: The online approach mandates that ingress Gateways instantly deposit zk-nyms received from clients to the NymAPI Quorum for verification. Once verified by the Quroum, the ingress Gateway is paid proprtional to the amount of bandwidth 'spent' with the zk-nym, and proceeds to grant the client access to the network.
- Offline: In contrast, the offline approach involves the periodic submission of collected zk-nyms by ingress Gateways to the Quorum, instead of an instant check. Subsequently, the Quorum nodes perform checks to detect any instances of double-spending and identify the public key associated with such occurrences, whereas the ingress Gateways only do a simple check to check that _that particular_ zk-nym had not been spent with itself before.
> The zk-nym system takes the **offline** approach.
## Offline Approach: Pros & Cons
The advantages of the offline approach are manifold:
- Immediate access to the Nym network upon zk-nym submission, eliminating any delays in service provisioning until payments are deposited and verified as would occur in the online approach.
- Alleviates performance strain on ingress Gateways and Quorum members, serving as a more efficient method compared to the online counterpart. By moving computationally intense work to the Quorum, this means that Gateway nodes are able to be run on less powerful machines, meaning more operators can more easily run them (and cover their costs) and thus increase the overall number and spread of Gateways around the globe.
- Moreover, the offline approach can circumvent the potential issue of overwhelming the blockchain with the serial numbers of spent coins.
However, the offline approach introduces certain limitations.
- Ingress Gateways accept zk-nyms without preemptively checking for instances of double spending thus making them susceptible to unknowingly accepting double-spent credentials.
- Any potential repercussions against double spenders can only be implemented once the user requests a new credential for their zk-nym Generator (aka they have to 'top up' and buy more bandwidth allowance), assuming they haven't altered their identifier (the Bech32 address).
An exploitable scenario arises from these limitations:
- A malicious user purchases bandwidth and aggregates a valid zk-nym credential in the standard way, worth $10 of crypto/fiat. Subsequently, the malicious user proceeds to sell the credential to 100 users for $1 each, allowing each user to generate zk-nym credits of 100MB from this **valid** credential. Under the offline approach, entry nodes forego double-spending checks; so long as the clients all used different ingress Gateways, all 100 users could access the network without obtaining a subscription. As bandwidth consumption is tracked locally between client and ingress node, and each zk-nym credit is rerandomised, there is no way that ingress Gateways would know that the zk-credential used by the client has been shared with other parties. This loophole highlights the need for stringent measures to counter such potential abuses within the system, without creating either speed bottlenecks (in the case of the Online model) or impacting the anonymity of the system. We can, however, mitigate this problem without doing either of these things.
## Solution to Offline Double Spending
To efficiently prevent the fraudulent use of tickets within the Nym network, a two-tiered solution is in place that combines (1) the immediate detection of double-spending attempts at the level of individuals ingress Gateways and (2) subsequent identification and blacklisting of offending clients at the Quorum level.
### Entry Node Implementation: Real-Time Ticket Unspending Validation
Each spent zk-nym credit contains as an attribute a unique serial number, which is revealed in plaintext to the respective ingress Gateway. Each Gateway has a copy of a [Bloom Filter](https://www.geeksforgeeks.org/bloom-filters-introduction-and-python-implementation/) - on receiving a credit, it will check against its copy of a local database to check whether this serial number has already been seen. If so, it rejects the credit as being double-spent and the client's connection request is rejected. If not, it will add the serial number to its local DB.
> Since each time a zk-nym credential is rerandomised its serial number is changed, the serial number being shared in no way identifies a client or user.
Each Gateway will periodically share their serial numbers with the Quorum and refresh their copy of the Bloom Filters from the Quorum, in order to refresh the global list shared by all ingress Gateways and the Quorum. See the step below for more on this.
> Crucially, ingress Gateways refrain from extensive computations to identify the original ticket owner, and avoids broadcasting information about the double-spending attempt to other ingress Gateways. The entry node is also not involved in any global blacklisting process of the clients. The sole purpose of this check is to swiftly identify any attempts at double-spending and add the seen ticket's serial number to the local DB cache.
### Nym-API Implementation: Blacklisting and Penalties for Double-Spenders
All Gateways periodically forward the collected credits to the Quorum, enabling them to pinpoint and blacklist any clients who double spend. Upon receiving the credits, the Quorum appends all the incoming serial numbers to the global list of spend zk-nym serial numbers and proceed with the identification process for any malicious users engaging in double-spending.
This identification phase involves looking for instances of double spending, identifying the id of the double-spending client, and blacklisting this client by its id. Subsequently, when this client requests a new credential, their plaintext public identifier is included in the request. The Quorum then checks if this identifier is blacklisted. If it is, a new credential is not issued. Furthermore, since the PSCs are only attainable after depositing NYM as payment, the Quorum has the authority to withhold the deposited NYMs as a punitive measure for any detected instances of double-spending.
<!-- extract parts of large diagram & upload as PNG to server + link -->
@@ -0,0 +1,48 @@
# Rerandomisation & Incremental Spend
Each zk-nym credit will not be valid for the entire amount of data that the credential aggregated from the PSCs is; if the aggregated credential is worth (e.g.) 10GB of Mixnet data, each credit will be worth far less (e.g. 100MB). This amount will be globally uniform in order to avoid situations where differently sized credits allow for patterns to emerge.
```admonish info
The functionality included in the following code block examples were added to the [nym-cli tool](../tools/nym-cli.md) for illustrative purposes only: this is not necessarily how credentials will be accessed in the future.
**Furthermore, the `nym-cli` uses the words 'tickets' in place of 'credits' and 'ticketbook' in place of 'aggregated credential': this is wording that we are moving away from now in place of the simpler credential/credit.** This will be updated in the `nym-cli` tool in a future release.
The numbers used in this high level overview are for illustration purposes only. The figures used in production will potentially vary. Note that individual zkNym sizes will be uniform across the Network.
```
## Why not spend the entire credential at once?
This is to account for the need for a client to change their ingress Gateway, either because the Gateway itself has gone down / is not offering the required bandwidth, or because a user might simply want to split their traffic across multiple Gateways for extra privacy.
This means that clients are not tied to particular Gateways they have 'spent' their entire subscription amount with; if the ingress Gateway goes down, or the client simply wishes to use another ingress Gateway, the user has multiple other zk-nym credits they can use that account for their remaining purchased bandwidth.
Going back to the `nym-cli` tool to illustrate this; we can generate multiple unlinkable credits ('tickets' on this command output) from a single aggregated credential ('ticketbook' below):
```
./nym-cli ecash generate-ticket --credential-storage storage.db --provider 6qidVK21zpHD298jdDa1RRpbRozP29ENVyqcSbm6hQrG --full
TICKETBOOK DATA:
4Ys9pzUf9MPxX4s5RASyrRoY9fPk1a1kFuPBP2jm2L5PyUy535yPEfjHAfpUTC1Lf2d155TmjukvcDycQYfBSDfhEUJM4J3qPNfG3B5aQEEkefESZp3CM5AEnAu1AEyhpepbYw6BuXokiNcmaYtq3yJQbA4KicKP8FowoRzKHmXpJoUqY8wYQughGfdtXgr3rVaZmK21X51P1NL2UW1aCE512WWfy6P1LJHByWywT3qVw28Z83
generating payment information for 50 tickets. this might take a while!...
AVAILABLE TICKETS
+-------+---------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------+
| index | binary data | spend status |
+============================================================================================================================================================================================+
| 0 | 4kgKyJLq1zQuk9r9AbEFHPqD8mDuxsLSjgo9XW4Lf7EqGSbgfNsWSEcTbRPEMFLzpstbX5azsA3opFh851h4g5qCG2qE3Luwqua4GG2ebJhk91rvEc5JPctbVQxL62fkfQ6svdcNp…1057bytes remaining | NOT SPENT |
|-------+---------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------|
| 1 | 4kefQqViRZd5YezMHH1FTcgUGPK2E2ivfmwgf59exvsnR8tsb5aJtGVwpA7wAJT6icPeo8jtDwDZ3WMPJxL3VRLiakAQr79zh7ixM89gowg3ChHEy6ewmHcT7T6RFkZFsMCMj1CNd…1057bytes remaining | NOT SPENT |
|-------+---------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------|
| 2 | 4kxaKdBxyFzJ8gxSZCh1v3wBfN7JvnCJuoJ4MWqkkMHtt2XgRKbDmHCv5ZxtA57Qk8LC3NDMBmqjADvY34mAPdT3tLBL4uxse9ASa227Ji96dwgxvfbpvLXSSr5o4vuPRV9K7UfpJ…1057bytes remaining | NOT SPENT |
|-------+---------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------|
| 3 | 4kdYwUJwXyxZBLQXextd4GsU2MATjzArVq5Ec459fTXyrm6q3vxurWULzBMpV5UjcmjJtnw1zFqt7f8Ydu5gyxwAVXP3Nwpn83ouguv2n4YrUewZCvFAqQYXgahhhaQGp6RxK2Arh…1057bytes remaining | NOT SPENT |
|-------+---------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------|
...
| 46 | 4kg8bfQ7kGgq5TkkqXagpAEu95gmGT4i7NKbaxJtp2gRgWRrQZM1rxaDAzAxfghoM6PFNbYgKsnLD4MF8HtXW3p92CnPBjswzJ1EbtsMGpgDER3CYFt2ivAhMAVXFziF5UjVJXhpa…1057bytes remaining | NOT SPENT |
|-------+---------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------|
| 47 | 4kipbH5Fqt5E9hFMynm9vzFh5FkxKRdHrSEiiJWDwmg3mASctR61sXoFD5u5ZMBwGdvz9sWsRfrpR4MX2NNfRhC85aUxqtkAv3hXZiCLtE1pUC54Cq7YXHyv2XTNKpvuFZs2GmwYg…1057bytes remaining | NOT SPENT |
|-------+---------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------|
| 48 | 4kxYZ26HXvxVhh4quHXeCUyQokydeF5wkwUi8fMx6P3uoMvuiPaNP1SJTbYnaQEFFtF6U4dGop6QckUYvbtwQFoGJTJesHFHTDtHbshj5Dg8DwbyaHuAR86zGwYMUPved4XKUTMLa…1057bytes remaining | NOT SPENT |
|-------+---------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------|
| 49 | 4kb6zmPebRxjKLVicctq2whvANjWJMoohiPBMr21cT4xj78nvXmJEK8EB4PpqQVFo6ddU9uzuer5ggQZNZgETX2VXBzymBYNzXBuXjLJi1WRdAiASqWz5Hv5im1TJh4XBE4mxKo8Q…1057bytes remaining | NOT SPENT |
+-------+---------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------+
```
@@ -0,0 +1,36 @@
# Unlinkability
Each time a credential is requested by an ingress Gateway to prove that a client has purchased data to send through the Mixnet, instead of sending that credential, the Requester's device will produce a zk-nym credit. This is a rereandomised value that is able to be verified as being legitimate (in that it was created by a valid root credential) but **not linked to any other credits**, either previously generated or to be generated in the future. This feature also allows for a credential to be split across multiple ingress Gateways / connections and [incrementally spent](./rerandomise.md) over time.
```admonish info
The functionality included in the following code block examples were added to the [nym-cli tool](../tools/nym-cli.md) for illustrative purposes only: this is not necessarily how credentials will be accessed in the future.
**Furthermore, the `nym-cli` uses the words 'tickets' in place of 'credits' and 'ticketbook' in place of 'aggregated credential': this is wording that we are moving away from now in place of the simpler credential/credit.** This will be updated in the `nym-cli` tool in a future release.
The numbers used in this high level overview are for illustration purposes only. The figures used in production will potentially vary. Note that individual zkNym sizes will be uniform across the Network.
```
```
./nym-cli ecash generate-ticket --credential-storage storage.db --provider 6qidVK21zpHD298jdDa1RRpbRozP29ENVyqcSbm6hQrG --ticket-index=3
TICKETBOOK DATA:
4Ys9pzUf9MPxX4s5RASyrRoY9fPk1a1kFuPBP2jm2L5PyUy535yPEfjHAfpUTC1Lf2d155TmjukvcDycQYfBSDfhEUJM4J3qPNfG3B5aQEEkefESZp3CM5AEnAu1AEyhpepbYw6BuXokiNcmaYtq3yJQbA4KicKP8FowoRzKHmXpJoUqY8wYQughGfdtXgr3rVaZmK21X51P1NL2UW1aCE512WWfy6P1LJHByWywT3qVw28Z83
attempting to generate payment for ticket 3...
PAYMENT FOR TICKET 3:
VfZAuVRRHekQYMvFevNAZmPPuwMAfEhTBY8TXatBysbrNXAg8euEGPpJvdbhNfQSznBb9nRSeBUSVoNTToSA6Uj5dXmJ7oE2rCB439DarLMWHWYfQNhw6yhWJhcg6bt7ebBYTs3vVeQgSB5kYuifzJF4QQmK6uJyTNPvpV1J6V8M32PBkGT3JpVB3GUGZiksETf7TaF9wAhMo2QAMxw5ZvaQVve5ea7Mane6cfb2Gx69SRff5zDfEQvKqKnyyZje4SGZgWUeHWVLhRjg4KMTJ3JcsHxEqj2k5qeGeyBbgzcuEtCpYvaytsz7nuZGJsT4Z87gB5Zq4NGuDmekuN977eRJvua2dASNWeHiAzVyvnS7ARN5cdUjjYKYiWgHaYrHGsv26WTDeiu4U3sdJMrLHGFY5ihX7f8sTZqD6Wx5AWjQNbEtKaVHymDogfLcwGCC42gQ2yhKfPUaWJ8H4yMB65YBDXGjATaUzcDmJcZKx8g31j2uTVNSFUesd5CRNEEcTNW7cSFFCishCD3T4eV9SuyZyEXAZ48pazPzc1BysBNHEXQNUEtEAZTKmpghC2pihhfDub6LnMJPo9DDdhCULCbcWbGAPc1vPekPaWvk7wrUTGwp5xoNUhQLW3MeJzMvrMSsqLdursCKB4h4Tk272WCStCPQwAKMYoxjWvMzxoUTTWCkhLKHruMtsehRnai4vhu13jbui6ji1F389gfazm4ctth2s4Yw3H3SaPtRETBfZNvZ7n5UV1MD6Q3qin92gT65iqXEi4zRN3woYcK6ZehiSvgUksdEFAUSxNMgNXKtHEYDS6kA37tn5JdBa2Ex2jLudFfhg6JBM226ZKyj65o6feYPgbJAR3jMCmQRHe6DSFb4aH895EowNMjfGUhwhmnbYB1djp7iFXxPP7575NAerhxEQ1WFnxTfoX7pu1Vc9YZb5priCAVbATCaDkECJsdedM45Vx96Jc6E5NWqD98RhMsPimVJkSfYJmRxH9qugica6WonFFb2YLvXYyhoBA1VHBcRqZJ5KHitS5AegYSoYprUfubMzcYo2hGVEQkGKAsFq6jZgCsbJoGLXt3No317vcowB5f3hqT9FjASHAzW2j8uJ9RRzX7XtrPhArwx4EyPgYzrvgG7xcenoSgQt8poa7aYky56eZTKHVUZgUEt6St32MjcivMvmNdWiAHHDc2ZxzTJHgeuCckX7n19vQ3XNLuXv9oGKNNCi8kHnT4tUnnGXNAWXWuyBgZKWUL8u3y41iW6dLYK3Pw5zfpKZTrq3q3bTLJRN5LnnUuFVnWsC3SNqa6VAAvhTGR9PzxLk8C6HeLP2AsYPpqeQwbaL3Ks6tvPdob3tQPWRBGL4uiKtNZ23tRYZGZLYFWZK7psRSZg5AETejKxztVzAuYovpVUiDq71o331tjqWWV1SzWT13Rd1uwz6nHtsjgao2863YaizKARcYr1j9MKtNfDs483yho6i7tbCRR9M4CPLqdiKEaRyVC1FP4F3sejA6nZTuAA35JWUzX6BBj7wgdypMLdMmmtcCZm3bRrF3GvJJs67U8JWRc6dnoGUDaD7rUu
```
Now lets generate another credit to spend either topping up once the previous one's data allowance has been used, or with another Gateway. Notice that the `ticket-index` is the same: this is generated from the same aggregated credential as the one above!
```
./nym-cli ecash generate-ticket --credential-storage storage.db --provider 6qidVK21zpHD298jdDa1RRpbRozP29ENVyqcSbm6hQrG --ticket-index=3
TICKETBOOK DATA:
4Ys9pzUf9MPxX4s5RASyrRoY9fPk1a1kFuPBP2jm2L5PyUy535yPEfjHAfpUTC1Lf2d155TmjukvcDycQYfBSDfhEUJM4J3qPNfG3B5aQEEkefESZp3CM5AEnAu1AEyhpepbYw6BuXokiNcmaYtq3yJQbA4KicKP8FowoRzKHmXpJoUqY8wYQughGfdtXgr3rVaZmK21X51P1NL2UW1aCE512WWfy6P1LJHByWywT3qVw28Z83
attempting to generate payment for ticket 3...
PAYMENT FOR TICKET 3:
Vev3SmwWtH5vbnejX5Zzc1EcxXAgveqHpKNN8arxXaWLhFcEpdcZ6n7qr3NrQUNURWsK2AsUiX8aSiGSjMPEY3iDE3aDYnjYERVow8RKUmQiYSKvz7v9cEJxt97JAHBfu9WYNHXTnLFSJwWuFtBdzY5dzPdzGckFenGCysa1ZBHGADHChDVXKoPHXxpn5qyJxmi48coUQDptR64QgkCeQ8RRZ396Lxw2NKFSjqavCMMDVm3g1rW7cYyPanBhkoAUzPU9KXX1rtmhD6F9gV89mGZ8fm7ByDuKuYU28seLQ7GkVKkhNeRW9XxbjSiyscTnMUzJ24R5VbSdr141BaquUHezdUTzmA2EjAtcyyiVrCMV13cc96CRbMXENP2soUzckFnh1qPnrfKCvX4JYkztq7UgPT2mZEnSTDW4C6Z2NVCNBPNLqUSYrU4id8Jzcp1mBxqJjdYcQ7P5fWJbT5Q9NAq44PCgfXpsUkNoj35QVQvKXKLb5oNGqnua5YC1WBPcENcpS7ZPWpk2hwe8VK4gNgnwQtWH2RPmWbvBREAV97vS1vKNHJyry9sD2PiMJGSmBnb1bKsGxR9UQN3YvRsdGHzyJHzAMTzxbFJBqMPmxjSHJR4UdwzhB81Ludu1RAffTvecWFxmWH5bNymCQjw3wey7Uequcxgyy8KAWYDzvHGwCZQbHQXghsYREiqquZWaa8hX3iTNBFUtEk8PRVT78MoFNdeBWNjsLr8zyZ5EGnf4kqmw3a91g5p5vywf6e3LgMu19VHjPSNtKMNXiatkPEVjsCuCppmV4sB7FsdKKWcMUSWLsdmrDBg9PStHr7NaJRzLL5E91gvysmB36Nob9cHeHSZj3wM4NVVjFfZeRqQf4bi7ahfXjeeBetgDpqx7JcbU6tTN4JpcGUpp7fp4MhTq7MeVQMLweGUVLqewKgAGzCvEmrK6dzLd3U1P9vkAAVZ3cCAKUywnHGxoxDeEfexP1g1EqJLtKNZVKPf7hSMWqGhoQ36K7y5GnyZ5YhQ7jcDME9orm5w4StoxoDdCPcjbakKG7UaTHuhd7tU1mUffXcEvVerkXoQK9SEaKvGks21RBhW86aHUzJWVbkiDzdaqjJWbmzLV8FKvNxNyzucoH2rq8LiHRMZfV1H3SkVSa4j2Ktw7ZGoQfdj8DgekxXSR2nHPfhybzKYXTBqFo2ACisxkjR4rXr9Xo6eYywQhQ1MP6aYgYCAXFGHPoFf7kx7Jns5sWvHRBdaMF65zeFF2m5NDuMWETtLgFfsyNgR84vfSqTfzj2gsUykRei7q9N4LKmiDwBALTAEcTvZpLtXBjc8JaB9PUeBw7DoSiSK376sGrQ9F6ZGTngXACNz1TbvYhtau4bDa6KC2Qn7wmoyrphpn7TtM1jdwGBxLcaEEWZKQHvWVfTyL2itjqnrcAZkxYdCj56oQYwpWfKQk3zJEUA6SYHqyJjaLNVK6u25j7969EWjdpTsJ8qSsZgXi3T7dQqiwintZbUUUKRq7egN1SGVnA6Wup91uKrYUWEWMqVu4g8ipmRsLD9iXHHr3yA21Cka7pqk1FxR9BFTAnkk1
```
These are both generated by the _same_ underlying credential and used in a way that they cannot be tied to each other. An ingress Gateway might (for instance) get 100 connection requests from 100 Nym clients, each validated with a zk-nym credi t. It has no way of knowing whether these are all from the same single subscription, or 100 different ones.
@@ -0,0 +1,45 @@
# What are zk-nyms?
The zk-nym scheme enables the creation and use of unlinkable, rerandomisable anonymous access credentials that are 'spent' with Gateways in order to anonymously prove that someone has paid for Mixnet access. This implementation incorporates elements of both the [Coconut Credential](./coconut.md) and [Offline Ecash](https://arxiv.org/pdf/2303.08221) schemes.
As outlined in the [overview](./zknym-overview.md) on the next page, zk-nyms allow for users to pay for Mixnet access in a manner that is **unlinkable to their payment account**; even with pseudonymous cryptocurrencies or fiat. This solves one of the fundamental privacy problems with the majority of VPNs and dVPNs in production today: the linkability of a user's session with their payment information, which can in the majority of cases be easily used to deanonymise them, either at the behest of an authority or by the service operators themselves.
> The current zk-nym scheme is non-generic in that it is only used for gating Mixnet access. A generic scheme based on zk-nyms is being actively researched in order to facilitate more generic and customisable anonymous credentials for other applications and services.
## Motivations
Most of the time, when we build system security, we think of _who_ questions:
- Has Alice identified herself (authentication)?
- Is Alice allowed to take a specific action (authorisation)?
However, _who_ is not necessarily a question we want to be asking when designing a system with anonymous access control. This scheme allows us to instead consider questions of _rights_, namely:
- Does the entity taking this action have a right to do _X_?
This allows a different kind of security. Many of the computer systems we talk to every day don't need to know _who we are_, they only need to know if the entity kicking off a request has the _right to use_ the system.
The zk-nym scheme allows for this move to take place. Credentials are generated cooperatively by decentralised, trustless systems, and once the credentials are generated, they can be _re-randomized_; entirely new credentials, which no one has ever seen before, can be presented to the ingress point of the Nym Network, and validated without being linkable back to the signatures produced by the Quorum of credential signers used to generate them, or any credentials previously used by an entity wanting access. These properties allow zk-nyms to act as something like cryptographic bearer tokens generated by decentralised systems. The tokens can be mutated so that they are not traceable, but still verified with the original permissions intact.
> TL;DR: Users present cryptographic claims encoded inside the credentials to get secure access to resources despite the systems verifying credential usage not being able to know who they are.
### Re-randomisation vs pseudonymity
We stand on the shoulders of giants. Ten years ago, Bitcoin showed the way forward by allowing people to control resource access without recourse to _who_ questions. Rather, in Bitcoin and succeeding blockchains, a private key proves a _right to use_.
But as we can now see, private keys in blockchain systems act only as a minor barrier to finding out _who_ is accessing resources. A Bitcoin or Ethereum private key is effectively a long-lived pseudonym which is easily traceable through successive transactions.
**zk-nyms allows us to build truly private systems rather than pseudonymous ones.**
## Features
Specifically, zk-nym is an implementation of a blinded, re-randomizable, selective disclosure threshold credential signature scheme.
Let's say you have a `message` with the content `This credential controls X` in hand. In addition to the normal `sign(message, secretKey)` and `verify(message, publicKey)` functions present in other signature schemes like RSA, the zk-nym credential scheme adds the following:
1. _[Blind signatures](https://en.wikipedia.org/wiki/Blind_signature)_ - disguises message content so that the signer can't see what they're signing. This defends users against signers: the entity that signed can't identify the user who created a given credential, since they've never seen the message they're signing before it's been _blinded_ (turned into seemingly random binary data). The scheme uses zero-knowledge proofs so that the signer can sign confidently without seeing the unblinded content of the message.
2. _Re-randomizable signatures_ - take a signature, and generate a brand new signature that is valid for the same underlying message `This credential controls X`. The new bitstring in the re-randomized signature is equivalent to the original signature but not linkable to it. So a user can generate multiple zk-nyms from a single credential source, unlinkable to any previous "shown" zk-nym. But the underlying content of the re-randomized credential is the same (including for things like double-spend protection). This once again protects the user against the signer, because the signer can't trace the signed message that they gave back to the user when it is presented. It also protects the user against the relying party that accepts the signed credential. The user can generate multiple re-randomized credentials repeatedly, and although the underlying message is the same in all cases, there's no way of tracking them by watching the user present the same credential multiple times.
3. _Selective disclosure of attributes_ - allows someone with the public key to verify some, but not all, parts of a message. So you could for instance selectively reveal parts of a signed message to some people, but not to others. This is a very powerful property of the scheme which is to be explored more in future work, potentially leading to diverse applications: voting systems, anonymous currency, privacy-friendly KYC systems, etc.
4. _[Threshold issuance](https://en.wikipedia.org/wiki/Threshold_cryptosystem)_ - allows signature generation to be split up across multiple nodes and decentralized, so that either all signers need to sign (_n of n_ where _n_ is the number of signers) or only a threshold number of signers need to sign a message (_t of n_ where _t_ is the threshold value).
Taken together, these properties provide privacy for applications when it comes to generating and using signatures for cryptographic claims. If you compare it to existing tech, you might think of it as a sort of supercharged decentralized privacy-friendly [JWT](https://jwt.io/).
@@ -0,0 +1,58 @@
# Generating and using zk-nym anonymous credentials
```admonish info
The first use-case of zk-nyms is for anonymously proving the right to use the Nym mixnet for privacy.
The Nym mixnet is - at the time of publication - free for everyone. However, soon™ it will be required for each connecting client to present a valid credential - a zk-nym - to their ingress Gateway to access the Mixnet.
Accessing zk-nym credentials will vary depending on use:
- Individual developers building on the mixnet will be able to get zk-nym credentials via something like a faucet.
- Larger application integrations will have their own 'under the hood' credential generation and distribution scheme to generate access credentials on behalf of their users automatically.
- NymVPN users will have a variety of payment methods avaliable to them. The vast majority, if not all of the steps outlined on this page, will happen under the hood from their perspective. _More on this soon_.
```
Generation of zk-nyms involves the following actors / pieces of infrastructure:
- **Requester needing a zk-nym** for example a single user using the NymVPN app, or a company purchasing zk-nyms to distribute to their app users, in the instance of an app integrating a Mixnet client via one of the SDKs. The Requester is represented by a Bech32 address on the Nyx blockchain.
- [NymAPI](https://nymtech.net/operators/nodes/nym-api.html) instances working together on signature generation and spent credential validation, referred to as the **NymAPI Quorum**. Members of the Quorum are a subset of the Nyx chain Validator set (other tasks they perform include a multisig used for triggering reward payouts to the Network Infrastructure Node Operators and maintaining the global Bloom Filter for double-spend protection).
- **OrderAPI**: an API creating crypto/fiat <> NYM swaps and then depositing the NYM tokens in a smart contract managed by the NymAPI Quroum for payment verification. Implementation details of the API will be released in the coming months.
Generation happens in 3 distinct stages:
- Key Generation & payment
- Issue credential
- Generate unlinkable zk-nyms for Nym Network access
From the perspective of the Requester most of this happens under the hood, but results in the creation and usage of an **unlinkable, rerandomisable anonymous proof-of-payment credential** - a zk-nym - with which to access the Mixnet without fear of doxxing themselves via linking app usage and payment information. The user experience is further enhanced by the fact that a single credential can be split into multiple small zk-nyms, meaning that a Requester may buy a large chunk of bandwidth but 'spend' this in the form of multiple zk-nyms with different ingress Gateways. Whilst this happens under the hood, what it affords the Requester is an ease of experience in that they have to 'top up' their bandwidth less and are able to chop and change ingress points to the Nym Network as they see fit, akin to the UX of most modern day VPNs and dVPNs.
## Key Generation & Payment
- First, a Cosmos [Bech32 address](https://docs.cosmos.network/main/build/spec/addresses/bech32) is created for the Requester. This is used to identify themselves when interacting with the OrderAPI via signed authentication tokens. This is the only identity that the OrderAPI is able to see, and is not able to link this to the zk-nyms that will be generated. This identity never leaves the Requesters device and there is no email or any personal details needed for signup. If a Requester is simply 'topping up' their subscription, the creation of the address is skipped as it already exists.
- The Requester also generates an ed25519 keypair: this is used to identify and authenticate them in the case of using zk-nyms across several devices as an individual user. However, this is never used in the clear: these keys are used as private attribute values within generated credentials which are verified via zero-knowledge.
- The Requester can then interact with various payment backends to pay for their zk-nyms with crypto, fiat options, or natively with NYM tokens.
- Payment options will trigger the OrderAPI. This will:
- Create a swap for <PAYMENT_AMOUNT> <> NYM tokens.
- Deposit these tokens with the NymAPI Quorum via a CosmWasm smart contract deployed on the Nyx blockchain.
- The Requester sends a request to each member of the Quorum requesting a zk-nym credential. This request is signed with their private key and includes the transaction hash of the NYM deposit into the deposit contract, performed either by themselves or the OrderAPI.
<!-- diagram that shows clearly how on the one hand, the Bech32 address is used to identify user towards the OrderAPI for payments, and on the other hand shows how the ed25519 keypair is for identification and authentication for using zk-nym creds -->
## Issue zk-nym
At this point, NYM tokens have been deposited into the smart contract controlled by the Quorum's multisig and a zk-nym credential has been requested. Next, each member of the Quorum who responds to the Requester's request for a zk-nym checks the validity and returns a PSC signed with part of the master key (since this is a threshold cryptsystem, not all members of the Quroum must respond to create a zk-nym, only enough to pass the threshold). The process looks like this:
- Members of the Quroum performs several checks to verify the request is valid:
- They verify the signature sent as part of the request is valid and that the request was made in the last 48 hours.
- They verify that the amount requested matches the amount deposited in the transation, the hash of which was signed by the Requester's ed25519 key and sent as part of the request.
- Members then create a partial blinded signature - a 'partial signed credential' ('PSC') - from their fragment of the master key generated and split amongst them at the beginning of the Quroum in the initial DKG ceremony.
- The member also creates a `key:value` entry in their local cache with the transaction hash as the key, and the PSC + encrypted signature as the value. This is used later for zk-nym validation and is cleaned after a predefined timeout.
- These PSCs are given back to the Requester after setting up a secure channel via DH key exchange, with each replying Quorum member also sending their public key for verification that the returned PSC was signed by them.
Once the Requester has received > threshold number of PSCs they can assemble them into a credential signed by the master key. The Requester never learns this master key (it is a private attribute) but the credential can be verified by the Quroum as being valid by checking for a proof that the credential's private attribute - the value of the master key - is valid.
![steps1-2](../images/zknym/deposit-generate.png)
## Spend zk-nym to Access Mixnet
- Once the credential has been aggregated from the PSCs returned from > threshold of Quorum members, smaller 'zk-nym credits' can be generated from it, accounting for smaller chunks of bandwidth which can be 'spent' with ingress Gateways. This occurs entirely offline, on the device of the zk-nym Requester. See pages on the scheme's [unlinkability](unlinkability.md) and [rerandomisation and incremental spending](./rerandomise.md) features for further information on this.
- This zk-nym credit is later presented to the Quorum by the Gateway that collected it, which is used to calculate reward percentages given to Nym Network infrastructure operators by the Quorum, with payouts triggered by their multisig wallet. Both ingress Gateways and the Quorum use spent zk-nym credits when engaging in [double spending protection](./double-spend-prot.md).
![step3](../images/zknym/use-zknym.png)
+4 -4
View File
@@ -7,9 +7,9 @@ use nym_bin_common::logging::setup_logging;
use nym_cli_commands::context::{get_network_details, ClientArgs};
use nym_validator_client::nyxd::AccountId;
mod coconut;
mod completion;
mod validator;
mod zknym;
#[derive(Debug, Parser)]
#[clap(name = "nym-cli")]
@@ -62,8 +62,8 @@ pub(crate) enum Commands {
Account(nym_cli_commands::validator::account::Account),
/// Sign and verify messages
Signature(nym_cli_commands::validator::signature::Signature),
/// Ecash related stuff
Ecash(nym_cli_commands::coconut::Ecash),
/// Zknym related stuff
Zknym(nym_cli_commands::zknym::Zknym),
/// Query chain blocks
Block(nym_cli_commands::validator::block::Block),
/// Manage and execute WASM smart contracts
@@ -104,7 +104,7 @@ async fn execute(cli: Cli) -> anyhow::Result<()> {
Commands::Signature(signature) => {
validator::signature::execute(signature, &network_details, mnemonic).await?
}
Commands::Ecash(coconut) => coconut::execute(args, coconut, &network_details).await?,
Commands::Zknym(zknym) => zknym::execute(args, zknym, &network_details).await?,
Commands::Block(block) => validator::block::execute(block, &network_details).await?,
Commands::Cosmwasm(cosmwasm) => {
validator::cosmwasm::execute(args, cosmwasm, &network_details).await?
@@ -3,26 +3,26 @@ use nym_network_defaults::NymNetworkDetails;
pub(crate) async fn execute(
global_args: ClientArgs,
coconut: nym_cli_commands::coconut::Ecash,
coconut: nym_cli_commands::zknym::Zknym,
network_details: &NymNetworkDetails,
) -> anyhow::Result<()> {
match coconut.command {
nym_cli_commands::coconut::EcashCommands::IssueTicketBook(args) => {
nym_cli_commands::coconut::issue_ticket_book::execute(
nym_cli_commands::zknym::ZknymCommands::IssueCredits(args) => {
nym_cli_commands::zknym::issue_credits::execute(
args,
create_signing_client(global_args, network_details)?,
)
.await?
}
nym_cli_commands::coconut::EcashCommands::RecoverTicketBook(args) => {
nym_cli_commands::coconut::recover_ticket_book::execute(
nym_cli_commands::zknym::ZknymCommands::RecoverCredits(args) => {
nym_cli_commands::zknym::recover_credits::execute(
args,
create_query_client(network_details)?,
)
.await?
}
nym_cli_commands::coconut::EcashCommands::ImportTicketBook(args) => {
nym_cli_commands::coconut::import_ticket_book::execute(args).await?
nym_cli_commands::zknym::ZknymCommands::ImportCredits(args) => {
nym_cli_commands::zknym::import_credits::execute(args).await?
}
}
Ok(())