Introduction

Welcome to the Nym Developer Portal, containing quickstart resources, user manuals, integration information, and tutorials outlining to start building privacy enhanced apps.

For more in-depth information about nodes, network traffic flows, clients, coconut etc check out the docs.

If you are looking for information and setup guides for the various pieces of Nym mixnet infrastructure (mix nodes, gateways and network requesters) and Nyx blockchain validators see the Operators Guides book.

If you’re looking for TypeScript/JavaScript related information such as SDKs to build your own tools, step-by-step tutorials, live playgrounds and more, make sure to check out the TS SDK Handbook.

Last change: 2024-04-11, commit: f978552

What is Nym?

Nym is a privacy platform that secures user data and protects against surveillance. It leverages the mixnet, a type of overlay network that makes both content and metadata of transactions private through network-level obfuscation and incentivisation, and Coconut, a privacy technology that creates an application-level private access control layer. Nym also utilises Nyx, our Cosmos SDK blockchain, to allow for us to use payment tokens in the form of NYM, as well as smart contracts, in order to create a robust, decentralised, and secure environment for the mixnet. In a nutshell, Nym is a solution that provides strong privacy protection for users in the digital world.

All the technical nuances about Nym platform can come out quite complex at first. Look for any questions in the FAQ section, take part in our DevRel AMAs or seek support in Nym’s community

An overlay network for network-level traffic privacy

Our mixnet design is based on the Loopix Anonymity System, somewhat modified to provide better quality of service guarantees.

In this brief video, our Head of Research and creator of the Loopix mixnet paper, Ania Piotrowska, delves into the design of the Loopix mixnet in depth at USENix 2017.

The Nym mixnet effectively addresses privacy concerns by utilizing network nodes to mix messages, making them unidentifiable to adversaries. Each packet is layer encrypted, and binary-padded so that it’s indistinguishable from all other packets. Incoming packets are “mixed” with all other messages inside the node. That is, the node strips one layer of packet encryption, and adds a small random transmission delay, so that messages are not emitted in the same order as which they arrived.

Next, the message is sent to another mix node, decrypted and mixed again, then to a third mixnode for further mixing. Finally, the message is delivered to its destination gateway.

As long as there’s enough traffic flowing through the nodes, even an adversary who can monitor the entire network cannot trace the packet flow through the system.

Privacy Enhanced Applications (PEApps) that need to defend against network-level monitoring can utilize the Nym mixnet to protect against network-level surveillance.

Revolutionising Privacy: An Incentivized Mixnet, the First of its Kind

Nym is the first mixnet to incentivise its node operators via a cryptocurrency: the NYM token. The tokenomic design of Nym ensures that nodes are motivated to provide top-notch performance and robust security, as they are financially rewarded for doing so. The video below contains an explanation of Nym’s tokenomic design from Nym’s Chief Scientist Claudia Diaz:

ELI5 Understanding of the Implications of Nym

Nym is a type of technology that is designed to keep your online activities private from surveillance networks which track users of many online services. As well as protecting the contents of your messages - the data - Nym’s design means that metadata - data about the data - is also kept private. This means that the location from which you sent your message, the time you did so, and a lot of information about your network connection is kept private: this is information that can be used to deanonymise users of other privacy systems, even if they employ encrypted messaging!

Nym works by “mixing” your data with other users’ data, making it much more difficult for anyone to single out and track just your information.

This system is unique because it provides an incentive for people to participate and help improve the network, making it stronger and more secure for everyone. By breaking down Nym and understanding its implications, you can see why it’s an important tool for anyone who values their privacy online.

Last change: 2024-04-11, commit: f978552

Nym vs Other Systems

Why use Nym: Understanding the Significance of Nym

Nym is the first system we’re aware of which provides integrated protection on both the network and transaction level at once. This seamless approach gives the best possible privacy protections, ensuring that nothing falls through the cracks between systems.

The diagram and brief explainer texts below give a high level overview of the difference between Nym and other comparable systems.

If you want to dig more deeply into the way traffic is packetised and moved through the mixnet, check out the Mixnet Traffic Flow page of the docs.

Nym vs VPNs

The most popular network-level privacy solution currently is the VPN (virtual private network), which provides network-level protection via an encrypted tunnel between a user’s computer and one run by a VPN provider. VPNs are often misconfigured, however, and even when configured correctly, don’t offer real privacy or adequate resistance to censorship.

VPN providers can also fully observe all network traffic between users and the public internet, knowing exactly what services its users are accessing at a given time. The user must trust that the VPN provider is not using their information in a malicious manner or keeping logs.

The Nym mixnet is an anonymous overlay network that provides strong network-level anonymity, even in the face of powerful systems capable of passively monitoring the entire network. The mixnet is decentralized, with no trusted third parties, and so does not require a trusted provider like a VPN. More importantly, Nym provides superior privacy to VPNs and can support high-quality of service and low latency through incentives.

Nym vs Tor

Tor is the best-known anonymous overlay network today. Unlike VPNs, Tor provides a ‘circuit’ of three hops that provides better privacy than single-node VPNs, so any single node in Tor can’t deanonymize traffic. Tor’s onion-routing encrypts traffic between each hop so that only the final hop, the Tor ‘exit node’, can decrypt the package.

However, Tor’s anonymity properties can be defeated by an entity that is capable of monitoring the entire network’s ‘entry’ and ‘exit’ nodes, because while onion-routing encrypts traffic, Tor does not add timing obfuscation or use decoy traffic to obfuscate the traffic patterns which can be used to deanonymize users. Although these kinds of attacks were thought to be unrealistic when Tor was invented, in the era of powerful government agencies and private companies, these kinds of attacks are a real threat. Tor’s design is also based on a centralized directory authority for routing.

While Tor may be the best existing solution for general-purpose web-browsing that accesses the entire internet, it is inarguable that mixnets are better than Tor for message-passing systems such as cryptocurrency transactions and secure messaging, and we believe well designed incentives can also enable the use of Nym as a general purpose decentralized VPN. The Nym mixnet provides superior privacy by making packets indistinguishable from each other, adding cover traffic, and providing timing obfuscation. Unlike both previous mixnet designs and Tor, the Nym mixnet decentralizes its shared operations using blockchain technology and uses incentives to both scale and provide censorship-resistance.

Nym vs I2P

I2P (‘Invisible Internet Project’) replaces Tor’s directory authority with a distributed hash table for routing. How to design a secure and private distributed hash table is still an open research question, and I2P is open to a number of attacks that isolate, misdirect, or deanonymize users. Like Tor, I2P is based on ‘security by obscurity’, where it is assumed that no adversary can watch the entire network. While security by obscurity may have been cutting-edge at the turn of the millennium, such an approach is rapidly showing its age.

Nym’s cutting-edge mixnet design guarantees network anonymity and resistance to surveillance even in the face of powerful deanonymizing attacks. Unlike I2P, Nym adds decoy traffic and timing obfuscation. Rather than a centralized directory authority or distributed hash table, Nym uses blockchain technology and economic incentives to decentralize its network.The Nym mixnet can anonymize metadata even against government agencies or private companies who can monitor network links and observe the incoming and outgoing traffic of all clients and servers.

Nym vs Facebook Connect

The Nym credential system decentralizes the functions of systems like Facebook Connect while adding privacy. Personal data has become a toxic asset, even to companies who base their entire business around it, as evidenced by the hack of Facebook’s OAuth identity system in 2018 and the subsequent release of the data of 50 million users.

Unlike Facebook Connect and similar OAuth-based services like Sign in with Google, traditional usernames and passwords, or even public/private key pairs, Nym credentials allow users to authenticate and authorize data sharing without unwillingly revealing any information to a third party. There is no central third party in charge of the credentials, and users remain totally in control of their own data, disclosing it only to those who they want to. A user can store their data wherever they want (including on their own devices), and unlike alternatives like W3C’s DIDs, a user does not store anything on the blockchain, offering better privacy.

Last change: 2024-04-11, commit: f978552

Node Types

Discover the workings of Nym’s privacy-enhancing mixnet infrastructure through the below video, where we break down the different types of nodes and how they each play a crucial role in ensuring secure and anonymous communication.

Where do I go from here? 💭

For more in-depth information on the network architecture, head to the Network Overview page, and check out the Operators book if you want to run a node yourself.

If you would like to concentrate on building an application that uses the mixnet:

Last change: 2024-04-11, commit: f978552

Overview

There are multiple options to quickly connect to Nym and play with both the mixnet and credentials on the Sandbox testnet.

At most, these involve running Nym as a second process alongside an existing application in order to send traffic through the mixnet, most are either interact webpages or a standalone app.

If you’ve already covered the information in this section, or want to jump straight into integrating/ a Nym connection into an existing application, head to the Integrations section.

Last change: 2024-04-11, commit: f978552

Chat demo (webapp)

You can find a browser-based ‘hello world’ chat app here.

Either open in two browser windows and send messages to yourself, or share with a friend and send messages to each other through the mixnet.

Last change: 2024-04-11, commit: f978552

Coconut Credential Playground (webapp)

There is a coconut-scheme based Credential Library playground here. This is a WASM implementation of our Coconut libraries which generate raw Coconut credentials. Test it to create and re-randomize your own credentials.

For more information on what is happening here check out the Coconut docs.

Last change: 2024-04-11, commit: f978552

SOCKS Proxy (CLI)

The socks5 client now also supports SOCKS4 and SOCKS4A protocols as well as SOCKS5.

The Nym socks5 client allows you to proxy traffic from a desktop application through the mixnet, meaning you can send and receive information from remote application servers without leaking metadata which can be used to deanonymise you, even if you’re using an encrypted application such as Signal.

Download or compile socks5 client

If you are using OSX or a Debian-based operating system, you can download the nym-socks5-client binary from our Github releases page.

If you are using a different operating system, head over to the Building from Source page for instructions on how to build the repository from source.

Initialise your socks5 client

Use the following command to initialise your socks5 client with the address of a Nym-operated Network Requester as a provider (the endpoint that will be proxying your traffic out of the mixnet) for ease:

./nym-socks5-client init --id quickstart --provider Entztfv6Uaz2hpYHQJ6JKoaCTpDL5dja18SuQWVJAmmx.Cvhn9rBJw5Ay9wgHcbgCnVg89MPSV5s2muPV2YF1BXYu@Fo4f4SQLdoyoGkFae5TpVhRVoXCF8UiypLVGtGjujVPf

You can always check out the list of endpoints you can use otherwise on the mixnet service provider explorer page.

Start your socks5 client

Now your client is initialised, start it with the following:

./nym-socks5-client run --id quickstart

Proxying traffic

After completing the steps above, your local socks5 Client will be listening on localhost:1080 ready to proxy traffic to the Network Requester set as the --provider when initialising.

When trying to connect your app, generally the proxy settings are found in settings->advanced or settings->connection.

Here is an example of setting the proxy connecting in Blockstream Green:

Blockstream Green settings

Most wallets and other applications will work basically the same way: find the network proxy settings, enter the proxy url (host: localhost, port: 1080).

In some other applications, this might be written as localhost:1080 if there’s only one proxy entry field.

Further reading

If you want to dig more into the architecture and use of the socks5 client check out its documentation here.

Last change: 2024-04-11, commit: f978552

NymConnect Beta (GUI)

NymConnect is a one-button GUI application that wraps around the nym-socks5-client for proxying application traffic through the Mixnet.

You can watch our video on getting started with NymConnect:

Install NymConnect and select an application that you want to privacy-enhance from the dropdown menu. For now, NymConnect can be used with Electrum Wallet, Keybase, desktop Telegram and Blockstream Green. Configure these to run via a SOCKS5 proxy and send their data through the Nym mixnet!

Please note that NymConnect is currently released in beta. Please report bugs via Github.

Usage instuctions

  • Download and install NymConnect.
  • Select your service provider from the dropdown menu.
  • Click connect - NymConnect will connect to a service provider and its SOCKS Proxy (IP) and Port will be displayed.
  • Click on IP or Port to copy their values to the clipboard.
  • Go to your app settings and look for the network/proxy settings. Select running via SOCKS5 proxy and paste the IP and Port values given by NymConnect.

Your traffic from that application will now run through the mixnet for privacy and unlinkability!

Last change: 2024-04-11, commit: f978552

NymVPN alpha

Nym proudly presents NymVPN alpha - a client that uses Nym Mixnet to anonymise all of a user’s internet traffic through either a 5-hop mixnet (for a full network privacy) or the faster 2-hop decentralised VPN (with some extra features).

You are invited to take part in the alpha testing of this new application. The following pages provide a how-to guide, explaining steps to install and run NymVPN CLI and GUI.

Here is how

  1. Go to the NymVPN testers form
  2. Fill and submit the form!
  3. To test the GUI, go here
  4. To test the CLI, go here
  5. Join the NymVPN matrix channel if you have any questions, comments or blockers

NymVPN alpha testing will last from 15th of January - 15th of February.

NOTE: NymVPN alpha is experimental software for testing purposes only.

NymVPN Overview

To understand what’s under the hood of NymVPN and the mixnet, we recommend interested developers to begin with Nym network overview and the Mixnet traffic flow pages.

The default setup of NymVPN is to run in 5-hop mode (mixnet):

                      ┌─►mix──┐  mix     mix
                      │       │
            Entry     │       │                   Exit
client ───► Gateway ──┘  mix  │  mix  ┌─►mix ───► Gateway ───► internet
                              │       │
                              │       │
                         mix  └─►mix──┘  mix

Users can switch to 2-hop only mode, which is a faster but less private option. In this mode traffic is only sent between the two Gateways, and is not passed between Mix Nodes.

The client can optionally do the first hop (local client to Entry Gateway) using Wireguard. NymVPN uses Mullvad libraries for wrapping wireguard-go and to setup local routing rules to route all traffic to the TUN virtual network device.

NymVPN Resources & Guides

Last change: 2024-04-11, commit: f978552

NymVPN - Desktop (GUI)

Info

Our alpha testing round is done with participants at live workshop events and the application in this stage may not work for everyone.

If you commit to test NymVPN alpha, please start with the user research form where all the steps will be provided. If you disagree with any of the conditions listed, please leave this page.

This is a desktop (GUI) version of NymVPN client. A demo of how the application will look like for majority of day-to-day users.

Follow the simple automated script below to install and run NymVPN GUI. If the script didn’t work for your distribution or you prefer to do a manual setup follow the steps in the guide for Linux or MacOS .

Visit NymVPN alpha latest release page to check sha sums or download the binaries directly.

Linux AppImage Automated Installation Method

The latest releases contain appimage.sh script. This method makes the installation simple for Linux users who want to run NymVPN from AppImmage. Executing the command below will download the binary to ~/.local/bin and verify the checksum:

curl -fsSL https://github.com/nymtech/nym-vpn-client/releases/download/nym-vpn-desktop-v0.0.13/appimage.sh | bash

Run with the command:

sudo -E ~/.local/bin/nym-vpn.appimage

Automated Script for GUI Installation (Linux and Mac)

We wrote a script which does download of dependencies and the application, sha256 verification, extraction, installation and configuration for Linux and MacOS users automatically. Turn off all VPNs and follow the steps below.

  1. Open a terminal window in a directory where you want the script to be downloaded and run
curl -o nym-vpn-desktop-install-run.sh -L https://gist.githubusercontent.com/tommyv1987/7d210d4daa8f7abc61f9a696d0321f19/raw/939ac8d0afed69f43739b9cf2e5728454ea2c437/nym-vpn-client-install-run.sh && chmod u+x nym-vpn-desktop-install-run.sh && sudo -E ./nym-vpn-desktop-install-run.sh
  1. Follow the prompts in the program

To start the application again, reconnect your wifi and run

# Linux .AppImage
sudo -E ~/nym-vpn-latest/nym-vpn-desktop_0.0.13_ubuntu-22.04_x86_64/nym-vpn_0.0.13_amd64.AppImage

# Linux .deb
sudo -E nym-vpn

# MacOS
sudo -E $HOME/nym-vpn-latest/nym-vpn

In case of errors check out the troubleshooting section.

Last change: 2024-04-11, commit: f978552

NymVPN alpha - Desktop: Guide for GNU/Linux

Info

NymVPN is an experimental software and it’s for testing purposes only. All users testing the client are expected to sign GDPR Information Sheet and Consent Form (shared at the workshop) so we use their results to improve the client, and submit the form NymVPN User research with the testing results.

Preparation

Any syntax in <> brackets is a user’s/version unique variable. Exchange with a corresponding name without the <> brackets.

Installation

  1. Open Github releases page and download the binary for Debian based Linux

  2. (Optional: if you don’t want to check shasum, skip this point) Verify sha hash of your downloaded binary with the one listed on the releases page. You can use a simple shasum command and compare strings (ie with Python) or run in the same directory the following command, exchanging <SHA_STRING> with the one of your binary, like in the example:

echo "<SHA_STRING>" | shasum -a 256 -c

# choose a correct one according to your binary, this is just an example
# echo "a5f91f20d587975e30b6a75d3a9e195234cf1269eac278139a5b9c39b039e807  nym-vpn-desktop_0.0.13_ubuntu-22.04_x86_64.tar.gz" | shasum -a 256 -c
  1. Extract files:
tar -xvf <BINARY>.tar.gz
# for example
# tar -xvf nym-vpn-desktop_0.0.13_ubuntu-22.04_x86_64.tar.gz
  1. If you prefer to run .AppImage make executable by running:
# make sure you cd into the right sub-directory after extraction
chmod u+x ./nym-vpn_0.0.13_amd64.AppImage
  1. If you prefer to use the .deb version for installation (works on Debian based Linux only), open terminal in the same directory and run:
# make sure you cd into the right sub-directory after extraction
sudo dpkg -i ./nym-vpn_0.0.13_amd64.deb
# or
sudo apt-get install -f ./nym-vpn_0.0.13_amd64.deb

Run NymVPN

For NymVPN to work, all other VPNs must be switched off! At this alpha stage of NymVPN, the network connection (wifi) must be reconnected after or in between the testing rounds.

In case you used .deb package and installed the client, you may be able to have a NymVPN application icon in your app menu. However this may not work as the application needs root permission.

Open terminal and run:

# .AppImage must be run from the same directory as the binary
sudo -E ./nym-vpn_0.0.13_amd64.AppImage

# .deb installation shall be executable from anywhere as
sudo -E nym-vpn

In case of errors, see troubleshooting section.

Last change: 2024-04-11, commit: f978552

NymVPN alpha - Desktop: Guide for Mac OS

Info

NymVPN is an experimental software and it’s for testing purposes only. All users testing the client are expected to sign GDPR Information Sheet and Consent Form (shared at the workshop) so we use their results to improve the client, and submit the form NymVPN User research with the testing results.

Preparation

Any syntax in <> brackets is a user’s/version unique variable. Exchange with a corresponding name without the <> brackets.

Installation

  1. Open Github releases page and download the binary for your version of MacOS

  2. Recommended (skip this point if you don’t want to verify): Verify sha hash of your downloaded binary with the one listed on the releases page. You can use a simple shasum command and compare strings (ie with Python) or run in the same directory the following command, exchanging <SHA_STRING> with the one of your binary, like in the example:

echo "<SHA_STRING>" | shasum -a 256 -c

# choose a correct one according to your binary, this is just an example
# echo "da4c0bf8e8b52658312d341fa3581954cfcb6efd516d9a448c76d042a454b5df  nym-vpn-desktop_0.0.13_macos_x86_64.zip" | shasum -a 256 -c
  1. Extract the downloaded file manually or by a command:
tar -xvf <BINARY>.tar.gz
# for example
# tar -xvf nym-vpn-desktop_0.0.13_macos_aarch64.tar.gz
  1. Mount the .dmg image you extracted by double clicking on it and move it (drag it) to your /Application folder

Run NymVPN

For NymVPN to work, all other VPNs must be switched off! At this alpha stage of NymVPN, the network connection (wifi) must be reconnected after or in between the testing rounds.

Run:

sudo /Applications/nym-vpn.app/Contents/MacOS/nym-vpn

# If it didn't start try to run with -E flag
sudo -E /Applications/nym-vpn.app/Contents/MacOS/nym-vpn

In case of errors check out the troubleshooting section.

Last change: 2024-04-11, commit: f978552

NymVPN alpha CLI Guide

Info

NymVPN is an experimental software and it’s for testing purposes only. All users testing the client are expected to sign GDPR Information Sheet and Consent Form (shared at the workshop) so we use their results to improve the client, and submit the form NymVPN User research with the testing results.

Installation

Any syntax in <> brackets is a user’s/version unique variable. Exchange with a corresponding name without the <> brackets.

  1. Open Github releases page and download the CLI latest binary for your system

  2. Verify sha hash of your downloaded binary with the one listed on the releases page. You can use a simple shasum command and compare strings (ie with Python) or run in the same directory the following command, exchanging <SHA_STRING> with the one of your binary, like in the example:

echo "<SHA_STRING>" | shasum -a 256 -c

# choose a correct one according to your binary, this is just an example
# echo "0e4abb461e86b2c168577e0294112a3bacd3a24bf8565b49783bfebd9b530e23  nym-vpn-cli_0.0.10_ubuntu-22.04_amd64.tar.gz" | shasum -a 256 -c
  1. Extract files:
tar -xvf <BINARY>.tar.gz
# for example
# tar -xvf nym-vpn-cli_0.0.10_ubuntu-22.04_x86_64.tar.gz
  1. Make executable:
# make sure you are in the right sub-directory
chmod u+x nym-vpn-cli

Run NymVPN

For NymVPN to work, all other VPNs must be switched off! At this alpha stage of NymVPN, the network connection (wifi) must be reconnected after or in between the testing rounds.

Make sure your terminal is open in the same directory as your nym-vpn-cli binary.

  1. Run it as root with sudo - the command will look like this with specified arguments:
# choose only one conditional --argument listed in {brackets}
sudo ./nym-vpn-cli { --exit-router-address <EXIT_ROUTER_ADDRESS>|--exit-gateway-id <EXIT_GATEWAY_ID>|--exit-gateway-country <EXIT_GATEWAY_COUNTRY> }
  1. To choose different Gateways, visit explorer.nymtech.net/network-components/gateways and copy-paste an identity key of your choice

Note

Nym Exit Gateway functionality was implemented just recently and not all the Gateways are upgraded and ready to handle the VPN connections. If you want to make sure you are connecting to a Gateway with an embedded Network Requester, IP Packet Router and applied Nym exit policy, visit this page, scroll down to the list and search Gateways with all the functionalities enabled.

  1. See all possibilities in command explanation section below

  2. In case of errors, see troubleshooting section

CLI Commands and Options

The basic syntax of nym-vpn-cli is:

# choose only one conditional --argument listed in {brackets}
sudo ./nym-vpn-cli { --exit-router-address <EXIT_ROUTER_ADDRESS>|--exit-gateway-id <EXIT_GATEWAY_ID>|--exit-gateway-country <EXIT_GATEWAY_COUNTRY> }

To see all the possibilities run with --help flag:

./nym-vpn-cli --help

Console output

Usage: nym-vpn-cli [OPTIONS] <--exit-router-address <EXIT_ROUTER_ADDRESS>|--exit-gateway-id <EXIT_GATEWAY_ID>|--exit-gateway-country <EXIT_GATEWAY_COUNTRY>>

Options:
  -c, --config-env-file <CONFIG_ENV_FILE>
          Path pointing to an env file describing the network
      --mixnet-client-path <MIXNET_CLIENT_PATH>
          Path to the data directory of a previously initialised mixnet client, where the keys reside
      --entry-gateway-id <ENTRY_GATEWAY_ID>
          Mixnet public ID of the entry gateway
      --entry-gateway-country <ENTRY_GATEWAY_COUNTRY>
          Auto-select entry gateway by country ISO
      --entry-gateway-low-latency
          Auto-select entry gateway by latency
      --exit-router-address <EXIT_ROUTER_ADDRESS>
          Mixnet recipient address
      --exit-gateway-id <EXIT_GATEWAY_ID>

      --exit-gateway-country <EXIT_GATEWAY_COUNTRY>
          Mixnet recipient address
      --enable-wireguard
          Enable the wireguard traffic between the client and the entry gateway
      --private-key <PRIVATE_KEY>
          Associated private key
      --wg-ip <WG_IP>
          The IP address of the wireguard interface used for the first hop to the entry gateway
      --nym-ipv4 <NYM_IPV4>
          The IPv4 address of the nym TUN device that wraps IP packets in sphinx packets
      --nym-ipv6 <NYM_IPV6>
          The IPv6 address of the nym TUN device that wraps IP packets in sphinx packets
      --nym-mtu <NYM_MTU>
          The MTU of the nym TUN device that wraps IP packets in sphinx packets
      --disable-routing
          Disable routing all traffic through the nym TUN device. When the flag is set, the nym TUN device will be created, but to route traffic through it you will need to do it manually, e.g. ping -Itun0
      --enable-two-hop
          Enable two-hop mixnet traffic. This means that traffic jumps directly from entry gateway to exit gateway
      --enable-poisson-rate
          Enable Poisson process rate limiting of outbound traffic
      --disable-background-cover-traffic
          Disable constant rate background loop cover traffic
  -h, --help
          Print help
  -V, --version
          Print version

Here is a list of the options and their descriptions. Some are essential, some are more technical and not needed to be adjusted by users.

Fundamental commands and arguments

  • --entry-gateway-id: paste one of the values labeled with a key "identityKey" (without " ")
  • --exit-gateway-id: paste one of the values labeled with a key "identityKey" (without " ")
  • --exit-router-address: paste one of the values labeled with a key "address" (without " ")
  • --enable-wireguard: Enable the wireguard traffic between the client and the entry gateway. NymVPN uses Mullvad libraries for wrapping wireguard-go and to setup local routing rules to route all traffic to the TUN virtual network device
  • --wg-ip: The address of the wireguard interface, you can get it here
  • --private-key: get your private key for testing purposes here
  • --enable-two-hop is a faster setup where the traffic is routed from the client to Entry Gateway and directly to Exit Gateway (default is 5-hops)

Advanced options

  • -c is a path to an enviroment config, like sandbox.env
  • --enable-poisson: Enables process rate limiting of outbound traffic (disabled by default). It means that NymVPN client will send packets at a steady stream to the Entry Gateway. By default it’s on average one sphinx packet per 20ms, but there is some randomness (poisson distribution). When there are no real data to fill the sphinx packets with, cover packets are generated instead.
  • --ip is the IP address of the TUN device. That is the IP address of the local private network that is set up between local client and the Exit Gateway.
  • --mtu: The MTU of the TUN device. That is the max IP packet size of the local private network that is set up between local client and the Exit Gateway.
  • --disable-routing: Disable routing all traffic through the VPN TUN device.

Testnet environment

If you want to run NymVPN CLI in Nym Sandbox environment, there are a few adjustments to be done:

  1. Create Sandbox environment config file by saving this as sandbox.env in the same directory as your NymVPN binaries:
curl -o sandbox.env -L https://raw.githubusercontent.com/nymtech/nym/develop/envs/sandbox.env
  1. Check available Gateways at nymvpn.com/en/alpha/api/gateways

  2. Run with a flag -c

sudo ./nym-vpn-cli -c <PATH_TO>/sandbox.env <--exit-router-address <EXIT_ROUTER_ADDRESS>|--exit-gateway-id <EXIT_GATEWAY_ID>|--exit-gateway-country <EXIT_GATEWAY_COUNTRY>>
Last change: 2024-04-11, commit: f978552

Troubleshooting

Below are listed some points which may need to be addressed when testing NymVPN alpha. If you crashed into any errors which are not listed, please contact us at the testing workshop or in the NymVPN Matrix channel.

NymVPN attempts to connect to sandbox testnet

If you testing the latest versions and you correctly expect the client to run over the mainnet, but it listens to https://sandbox-nym-api1.nymtech.net, it’s probably because of your previous configuration.

Check your config.toml either in the directory from which you run your client or in ~/.config/nym-vpn/ and remove sandbox.env from the config file and folder.

If the problem persists (probably due to some locally cache) download mainnet.env and save it to the same directory.

Running GUI failed due to TOML parse error

If you see this error when running NymVPN alpha desktop, it’s because the older versions needed entry location in config.toml configuration file. From v0.0.3 the entry location is selected directly by the user in the application. This error is due to an old app-data.toml config in your computer.

2024-02-15T14:25:02.745331Z ERROR read: nym_vpn_desktop::fs::storage: TOML parse error at line 5, column 1
  |
5 | [entry_node_location]
  | ^^^^^^^^^^^^^^^^^^^^^
wanted exactly 1 element, more than 1 element
 self=AppStorage { data: AppData { monitoring: None, autoconnect: None, killswitch: None, entry_location_selector: None, ui_theme: None, ui_root_font_size: None, vpn_mode: None, entry_node_location: None, exit_node_location: None }, dir_path: "/home/companero/.local/share/nym-vpn", filename: "app-data.toml", full_path: "/home/companero/.local/share/nym-vpn/app-data.toml" }
Error: TOML parse error at line 5, column 1
  |
5 | [entry_node_location]
  | ^^^^^^^^^^^^^^^^^^^^^
wanted exactly 1 element, more than 1 element

Simply delete this file app-data.toml from the path listed in the error message. In the example above it would be /home/companero/.local/share/nym-vpn/app-data.toml.

The application will create a new one on startup.

Thread main panicked

If you see a message like:

thread 'main' panicked at /Users/runner/.cargo/git/checkouts/mullvadvpn-app-a575cf705b5dfd76/ccfbaa2/talpid-routing/src/unix.rs:301:30:

Restart your wifi connection and start again.

MacOS alert on NymVPN UI startup

If you are running NymVPN on mac OS for the first time, you may see this alert message:

  1. Head to System Settings -> Privacy & Security and click Allow anyway

  1. Confirm with your password or TouchID

  2. Possibly you may have to confirm again upon running the application

Last change: 2024-04-11, commit: f978552

Frequently Asked Questions

NymVPN Support & FAQ page contains all essential FAQs regarding the client. This page (below) is a source of additional information often seeked by users, operators and developers testing NymVPN.

If you interested to read more about Nym platform, you can have a look at Nym general FAQ and read through Nym’s technical documentation, Developer Portal and Operators Guide.

NymVPN

If this your first time hearing about NymVPN, make sure you visit NymVPN webpage, the official NymVPN support & FAQ page and the proceed to the introduction and guide on how to install, run and test the client.

Below are some extra FAQs which came out during the previous alpha testing rounds.

What’s the difference between 2-hops and 5-hops

The default is 5-hops (including Entry and Exit Gateways), which means that the traffic goes from the local client to Entry Gateway -> through 3 layers of Mix Nodes -> to Exit Gateway -> internet. this option uses all the Nym Mixnet features for maximum privacy.

                      ┌─►mix──┐  mix     mix
                      │       │
            Entry     │       │                   Exit
client ───► Gateway ──┘  mix  │  mix  ┌─►mix ───► Gateway ───► internet
                              │       │
                              │       │
                         mix  └─►mix──┘  mix

The 2-hop option is going from the local client -> Entry Gateway -> directly to Exit Gateway -> internet. This option is good for operations demanding faster connection. Keep in mind that this setup by-passes the 3 layers of Mix Nodes. The anonymising features done by your local client like breaking data into same-size packets with inserting additional “dummy” ones to break the time and volume patterns is done in both options.

            Entry         Exit
client ───► Gateway ────► Gateway ───► internet

We highly recommend to read more about Nym network overview and the Mixnet traffic flow.

Why do I see different sizes of packets in my terminal log?

One of features of Nym Mixnet’s clients is to break data into the same size packets called Sphinx, which is currently ~2kb. When running NymVPN, the data log shows payload sizes, which are the raw sizes of the IP packets, not Sphinx. The payload sizes will be capped by the configured MTU, which is set around 1500 bytes.

What is ‘poisson filter’ about?

By default --enable-poisson is disabled and packets are sent from the local client to the Entry Gateway as quickly as possible. With the poisson process enabled the Nym client will send packets at a steady stream to the Entry Gateway. By default it’s on average one sphinx packet per 20ms, but there is some randomness (poisson distribution). When there are no real data to fill the sphinx packets with, cover packets are generated instead.

Enabling the poisson filter is one of the key mechanisms to de-correlate input and output traffic to the Mixnet. The performance impact however is dramatic: 1 packer per 20ms is 50 packets / sec so ballpark 100kb/s. For mobile clients that means constantly sending data eating up data allowance.

Nym Mixnet Architecture and Rewards

We have a list of questions related to Nym Nodes and the incentives behind running them under FAQ pages in our Operators Guide. For better knowledge about Nym architecture we recommend to read Nym network overview and the Mixnet traffic flow in our technical documentation.

Project Smoosh

Project Smoosh is a code name for a process in which different components of Nym Mixnet architecture get smooshed into one binary. Check out Smoosh FAQ in Operators Guide to read more.

Exit Gateway

Part of the the transition under code name Project Smoosh is a creation of Nym Exit Gateway functionality. The operators running Gateways would have to “open” their nodes to a wider range of online services, in a similar fashion to Tor exit relays. The main change will be to expand the original short allowed.list to a more permissive setup. An exit policy will constrain the hosts that the users of the Nym VPN and Mixnet can connect to. This will be done in an effort to protect the operators, as Gateways will act both as SOCKS5 Network Requesters, and exit nodes for IP traffic from Nym VPN and Mixnet clients.

  • Read more how the exit policy gets implemented here
  • Check out Nym Operators Legal Forum
  • Do reach out to us with any experiences you may have running Tor Exit relays or legal findings and suggestions for Nym Exit Gateway operators

Nym Integrations and SDKs

If you are a dev who is interested to integrate Nym, have a look on our SDK tutorials:

Last change: 2024-04-11, commit: f978552

Monero NymConnect Integration

New Nym mixnet integration launched for Monero desktop to secure the right to financial privacy and censorship-resistance

Financial privacy is an important component of digital currencies and the use of Nym will provide users with the highest level of privacy at the infrastructure level. All users of digital currencies should be afforded equal rights to protection from financial surveillance.

A team made up of Monero community members have successfully set up a service provider to use Monero (using the Monero desktop wallet) over the Nym mixnet. This allows Monero users to easily use NymConnect to run Monero over the mixnet, thereby enhancing the privacy of Monero transactions.

How can I use Monero over the Nym mixnet?

Any syntax in <> brackets is a user’s unique variable. Exchange with a corresponding name without the <> brackets.

The mainnet service provider to Monero over the Nym mixnet is now ready for use via NymConnect.

  • Download the latest version of NymConnect.
  • Make sure your NymConnect is executable.
# in Linux open terminal in the same folder and run:
chmod +x ./nym-connect_<YOUR_VERSION>.AppImage
  • Open NymConnect app
  • Turn it on - Monero wallet is listed in the apps supported by default, no need for any setup
  • Copy the Socks5 address and Port

Then go to your Monero wallet (desktop or CLI) and change the settings to run over socks5 proxy:

Monero desktop wallet:

  • Settings -> Interface -> Socks5 proxy -> Add values: IP address 127.0.0.1, Port 1080 (the values copied from NymConnect)

CLI wallet

  • Monerod: add --proxy 127.0.0.1:1080 --bootstrap-daemon-proxy 127.0.0.1:1080 to args

  • Monero-wallet-{rpc, cli}: add --proxy 127.0.0.1:1080 --daemon-ssl-allow-any-cert to args

For those who want to try it out in testnet, a stagenet service provider is also available: https://nymtech.net/.wellknown/connect/service-providers.json

Now your Monero traffic is protected by the network privacy of Nym Mixnet.

Last change: 2024-04-11, commit: f978552

Matrix NymConnect Integration

Chat applications became an essential part of human communication. Matrix chat has end to end encryption on protocol level and Element app users can sort their communication into spaces and rooms. Now the Matrix communities can rely on network privacy as NymConnect supports Matrix chat protocol.

Currently there is no option in Matrix’s Element client to set a Socks5 proxy. In order to use Element via NymConnect users have to start it from the command-line. The setup is simple, for convenience a keyboard shortcut setting or terminal alias can be easily done.

Setup & Run

Make sure you have installed and started NymConnect on your desktop.

To then start Matrix’s Element client via a Socks5 proxy connected to NymConnect, open terminal and run:

Linux

element-desktop --proxy-server=socks5://127.0.0.1:1080

Mac

open -a Element --args --proxy-server=socks5://127.0.0.1:1080

Optimise setup with a keybinding / alias

Keybinding

An eloquent solution to avoid entering a command every time is to setup your keybinding. Open your settings, navigate to Keyboard Shortcuts and choose to Set Custom Shortcut. Name and Shortcut fields are up to your preference, to the Command line add:

element-desktop --proxy-server=socks5://127.0.0.1:1080

Make sure your Shortcut isn’t already taken by something else in the menu.

An example can look like this.

Alternatively you can add a keybinding via the CLI, using whatever config files you edit for your given desktop environment / window manager.

Create an alias

If you prefer to simply shorten the length of the command (or all your keybindings are already taken) then you can simply create an alias for this long-winded command (this example aliases that command to the single word element, but you can replace it with whatever you like):

Linux

alias element="element-desktop --proxy-server=socks5://127.0.0.1:1080"

To make this alias persist, then add this to your .bashrc or .zshrc file (usually located in your $HOME directory) and source that file. This can be done by appending the alias command directly to the shell config file with one command.

For bash enter:

alias element="element-desktop --proxy-server=socks5://127.0.0.1:1080" >> ~/.bashrc

For zsh enter:

alias element="element-desktop --proxy-server=socks5://127.0.0.1:1080" >> ~/.zshrc

You can add the alias manually by opening your $HOME directory, enable hidden files (press ctrl + h) and open .bashrc or .zshrc file (based on your terminal setup) in a text editor, paste the string alias element="element-desktop --proxy-server=socks5://127.0.0.1:1080" to the the end, save and exit. Start a new terminal and run element.

Mac

alias element="open -a Element --args --proxy-server=socks5://127.0.0.1:1080"

To make this alias persist, then add this to your .zshrc (or .bashrc/.profile) file (usually located in your $HOME directory) and source that file. This can be done by appending the alias command directly to the shell config file with one command.

For zsh enter:

alias element="open -a Element --args --proxy-server=socks5://127.0.0.1:1080" >> ~/.zshrc

For .bashrc or .profile just change the end of the command.

You can add the alias manually by opening your $HOME directory, enable hidden files (in Finder press Shift + Command + .) and open .zshrc file (or .bashrc/.profile) in a text editor, paste the string alias element="open -a Element --args --proxy-server=socks5://127.0.0.1:1080" to the the end, save and exit. Start a new terminal and run element.

Now you can run Element through the Nym Mixnet with a single-word command.

Last change: 2024-04-11, commit: f978552

Telegram NymConnect Integration

This is a shortened version of a Nym Community post written by Saliveja.

The purpose of the following manual is not to promote Telegram but so people can use it with the Nym mixnet if they wish to, should a situation ask for that. This privacy-enhances Telegram at the network level and allows users to access the application from locations like where the application was banned.

See also: Element (Matrix) over the Nym mixnet: private, decentralised and secure messaging.

Setup & Run

Here’s how to configure Telegram with NymConnect:

  1. Download and install NymConnect(https://nymtech.net/download-nymconnect/). For more releases, check out Github. NymConnect is available for Linux, Windows, and MacOS. On Linux make sure NymConnect is executable. Opening a terminal in the same directory and run:
    chmod +x ./<VERSION>
    
  2. Start NymConnect Telegram is added to NymConnect by default.
  3. Click connect - the host and port will now be displayed.
  4. Click on host or port to copy the value to the clipboard.
  5. Open the Telegram proxy settings. Linux: Telegram -> Settings -> Advanced -> Connection type -> Use custom proxy MacOS: Telegram -> Settings -> Advanced -> Data & Storage -> Connection Type -> Use custom Proxy Windows: Telegram -> Settings -> Data and Storage -> Use proxy
  6. Add a proxy with the Add proxy button.
  7. Select SOCKS5 and make sure the port details are the same as those generated by NymConnect. Alternatively, follow this link: https://t.me/socks?server=127.0.0.1&port=1080
  8. Save the proxy settings in Telegram.
  9. Telegram is now running through the Nym Mixnet and is privacy-enhanced! This allows you to connect from regions which blocked Telegram.
  10. Note if you remain idle on Telegram for a while you might lose connectivity and your messages might not get through via SOCKS5 proxy. If that happens reconnect your NymConnect and reset the proxy again.

Follow this video to see the steps on Telegram setup.

Now your Telegram runs over NymConnect.

NymConnect is currently available for several applications and service providers. Support for more apps is on the way. For any bug reports or feedback please reach out to us on Telegram or our Discord server.

Last change: 2024-04-11, commit: f978552

Electrum Wallet NymConnect Integration

Electrum is one of the most favorite Bitcoin wallet for desktop users and it is used as a backend wallet for various crypto aplications in smart phones. Electrum was among the first integrations of Nym. This easy setup allows users to enhance privacy when managing the flagship of blochain cryptocurencies Bitcoin.

How can I use Bitcoin over the Nym mixnet?

Any syntax in <> brackets is a user’s unique variable. Exchange with a corresponding name without the <> brackets.

NymConnect Installation

NymConnect application is for everyone who does not want to install and run nym-socks5-client. NymConnect is plug-and-play, fast and easy use. Electrum Bitcoin wallet, Monero wallet (desktop and CLI) and Matrix (Element app) connects through NymConnect automatically to the Mixnet.

  1. Download NymConnect
  2. On Linux and Mac, make executable by opening terminal in the same directory and run:
chmod +x ./nym-connect_<VERSION>
  1. Start the application
  2. Click on Connect button to initialise the connection with the Mixnet
  3. Anytime you’ll need to setup Host and Port in your applications, click on IP and Port to copy the values to clipboard
  4. In case you have problems such as Gateway Issues, try to reconnect or restart the application

Electrum Bitcoin wallet via NymConnect

To download Electrum visit the official webpage. To connect to the Mixnet follow these steps:

  1. Start and connect NymConnect (or nym-socks5-client)
  2. Start your Electrum Bitcoin wallet
  3. Go to: Tools -> Network -> Proxy
  4. Set Use proxy to ✅, choose SOCKS5 from the drop-down and add the values from your NymConnect application
  5. Now your Electrum Bitcoin wallet runs through the Mixnet and it will be connected only if your NymConnect or nym-socks5-client are connected.

Electrum Bitcoin wallet setup

Last change: 2024-04-11, commit: f978552

Firo-Electrum Wallet NymConnect Integration

Firo (formerly Zcoin) is a privacy focused, zk-proof based cryptocurrency. Now users can enjoy Firo with network privacy by Nym as Firo’s fork of Electrum wallet was integrated to work behind the Mixnet. Read more about Firo on their official webpage.

How can I use Firo over the Nym Mixnet?

Any syntax in <> brackets is a user’s unique variable. Exchange with a corresponding name without the <> brackets.

NymConnect Installation

NymConnect application is for everyone who does not want to install and run nym-socks5-client. NymConnect is plug-and-play, fast and easy use. Electrum Bitcoin wallet, Monero wallet (desktop and CLI) and Matrix (Element app) connects through NymConnect automatically to the Mixnet.

  1. Download NymConnect
  2. On Linux and Mac, make executable by opening terminal in the same directory and run:
chmod +x ./nym-connect_<VERSION>
  1. Start the application
  2. Click on Connect button to initialise the connection with the Mixnet
  3. Anytime you’ll need to setup Host and Port in your applications, click on IP and Port to copy the values to clipboard
  4. In case you have problems such as Gateway Issues, try to reconnect or restart the application

Firo Electrum wallet via NymConnect

To download Firo Electrum wallet visit the Firo’s repository or Github release page. To connect to the Mixnet follow these steps:

  1. Start and connect NymConnect (or nym-socks5-client)
  2. Start your Firo Electrum wallet
  3. Go to: Tools -> Network -> Proxy
  4. Set Use proxy to ✅, choose SOCKS5 from the drop-down and add the values from your NymConnect application
  5. Now your Firo Electrum wallet runs through the Mixnet and it will be connected only if your NymConnect or nym-socks5-client are connected.

Firo Electrum wallet setup

Last change: 2024-04-11, commit: f978552

Custom Services

Custom services involve two pieces of code that communicate via the mixnet: a client, and a custom server/service. This custom service will most likely interact with the wider internet / a clearnet service on your behalf, with the mixnet between you and the service, acting as a privacy shield.

  • PasteNym is a private pastebin alternative. It involves a browser-based frontend utilising the Typescript SDK and a Python-based backend service communicating with a standalone Nym Websocket Client. If you’re a Python developer, start here!.

  • Nostr-Nym is another application written by NoTrustVerify, standing between mixnet users and a Nostr server in order to protect their metadata from being revealed when gossiping. Useful for Go and Python developers.

  • Spook and Nym-Ethtx are both examples of Ethereum transaction broadcasters utilising the mixnet, written in Rust. Since they were written before the release of the Rust SDK, they utilise standalone clients to communicate with the mixnet.

  • NymDrive is an early proof of concept application for privacy-enhanced file storage on IPFS. JS and CSS, and a good example of packaging as an Electrum app.

Last change: 2024-04-11, commit: f978552

Apps Using Network Requesters

These applications utilise custom app logic in the user-facing apps in order to communicate using the mixnet as a transport layer, without having to rely on custom server-side logic. Instead, they utilise existing Nym infrastructure - Network Requesters - with a custom whitelist addition.

If you are sending ‘normal’ application traffic, and/or don’t require and custom logic to be happening on the ‘other side’ of the mixnet, this is most likely the best option to take as a developer who wishes to privacy-enhance their application.

Nym will soon be switching from a whitelist-based approach to a blocklist-based approach to filtering traffic. As such, it will soon be even easier for developers to utilise the mixnet, as they will not have to run their own NRs or have to add their domains to the whitelist

  • DarkFi over Nym leverages Nym’s mixnet as a pluggable transport for DarkIRC, their p2p IRC variant. Users can anonymously connect to peers over the network, ensuring secure and private communication within the DarkFi ecosystem. Written in Rust.

  • MiniBolt is a complete guide to building a Bitcoin & Lightning full node on a personal computer. It has the capacity to run network traffic (transactions and syncing) over the mixnet, so you can privately sync your node and not expose your home IP to the wider world when interacting with the rest of the network!

  • Email over Nym is a set of configuration options to set up a Network Requester to send and recieve emails over Nym, using something like Thunderbird.

Last change: 2024-04-11, commit: f978552

Browser only

With the Typescript SDK you can run a Nym client in a webworker - meaning you can connect to the mixnet through the browser without having to worry about any other code than your web framework.

  • NoTrustVerify have set up an example application using mixFetch to fetch crypto prices from CoinGecko over the mixnet.

  • There is a coconut-scheme based Credential Library playground here. This is a WASM implementation of our Coconut libraries which generate raw Coconut credentials. Test it to create and re-randomize your own credentials. For more information on what is happening here check out the Coconut docs.

  • You can find a browser-based ‘hello world’ chat app here. Either open in two browser windows and send messages to yourself, or share with a friend and send messages to each other through the mixnet.

Last change: 2024-04-11, commit: f978552

Monorepo examples

As well as these examples, there are a bunch of examples for each SDK in the Nym monorepo.

Last change: 2024-04-11, commit: f978552

Integration Options

If you’ve already gone through the different Quick Start options and had a look at the tutorials, you have seen the possibilities available to you for quickly connecting existing application code to another Nym process.

Below are a resources that will be useful for either beginning to integrate mixnet functionality into existing application code or build a new app using Nym.

  • We suggest you begin with this integration decision tree. This will give you a better idea of what pieces of software (SDKs, standalone clients, service providers) your integration might involve, and what is currently possible to do with as little custom code as possible.

  • The integrations FAQ has a list of common questions regarding integrating with Nym and Nyx, as well as commonly required links.

  • To get an idea of what is possible / has already been built, check the community applications and resources page, as well as the developer tutorials codebase.

If you wish to integrate with the Nyx blockchain to use NYM for payments, start with the payment integration page.

Last change: 2024-04-11, commit: f978552

Integrating with Nyx for payments

If you want to integrate with Nym in order to send NYM tokens (for instance, if running a NYM <-> BTC swap application, or using NYM for payments), then you will need to interact with the Nyx blockchain.

Nyx is the blockchain supporting the Nym network, hosting both the NYM and NYX cryptocurrencies, the CosmWasm smart contracts keeping track of the network, and (coming soon) facilitating zk-Nym credential generation. It is built with the Cosmos SDK.

Interacting with the Nyx blockchain

Check out the integration options in the Integration FAQ.

Chain information and RPC endpoints

You can find most information required for integration in the Cosmos Chain Registry and Keplr Chain Registry repositories.

We recommend that users wanting to integrate with Nyx for cryptocurrency payments set up their own RPC Node, in order to be able to reliably query the blockchain and send transactions without having to worry about relying on 3rd party validators.

The guide to setting up an RPC node can be found here.

Last change: 2024-04-11, commit: f978552

Rust SDK

The Rust SDK allows developers building applications in Rust to import and interact with Nym clients as they would any other dependency, instead of running the client as a seperate process on their machine.

Read the docs.

Last change: 2024-04-11, commit: f978552

Interacting with a Cosmos SDK Blockchain via the Mixnet with the Rust SDK

This tutorial is for Rust developers wanting to interact with the Rust SDK and take a first step at building a service with which to interact with a Cosmos SDK blockchain.

The key here is to think of the service as a proxy: it interacts with the blockchain on the client’s behalf, shielding the client from the Validator it interacts with, whilst also being shielded from the client by the mixnet.

This service also nicely highlights the limitations of the mixnet - even though with this code your metadata is shielded from the Validator, and even the service does not know your Nym address, application-level information such as a blockchain address is not made private, in virtue of the fact that using the mixnet provides solely network-level privacy. For information on what application-level privacy Nym offers, check out the coconut credential SDK example.

Last change: 2024-04-11, commit: f978552

Tutorial Overview

This tutorial involves writing two pieces of code in Rust:

  • A client side binary used to construct a blockchain query and send this query to a service, which will query the Cosmos SDK blockchain and then pass the response back to the client (bear in mind this principle works for all blockchains - we’re just utilising the cosmrs library to interact with the Sandbox testnet blockchain in this tutorial). This query will be to query the balance of an account, in preparation for spending these tokens on a bandwidth credential in a subsequent tutorial.
  • A service which will listen out for requests from the mixnet, act on those requests, and anonymously reply to the client sending the requests.

You will learn how to do the following with the Rust SDK:

  • Create clients with manual storage settings.
  • Parse incoming traffic from the mixnet and reply anonymously using SURBs.

Services usually run on remote servers to assure reliable uptime and to unlink sender and receiver metadata. For demonstration purposes however, you will run both components on your local machine, looping messages through the mixnet to yourself.

You can find the code for these components here. You can use it as a reference while building or simply download it and follow along as you progress through the tutorial.

Notice that this tutorial attempts to use very few external libraries. This tutorial is not showing you how to build production-grade code, but to understand how to connect and send messages to, as well as receive messages from, the mixnet.

Sidenote: What is a Service / Service Provider?

‘Service’ or ‘Service Provider’ are catchall names used to refer to any type of app that can communicate with the mixnet via a Nym client - in this case, one embedded in its app process via the Rust SDK.

The first SP to have been released is the Network Requester - a binary that receives a network request from the mixnet, performs that request (e.g. authenticating with a message server and receiving new messages for a user) and then passes the response back to the user who requested it anonymously, shielding their metadata from the message server.

The SP you will build in this tutorial is far more simple than this, showing you how to approach building something that can:

  • connect to the mixnet,
  • listen for messages, and
  • perform some action with them - in this case, query a Cosmos SDK blockchain.

However, once you see how easy it is to integrate with the mixnet for traffic transport, you will be able to build apps with real-world uses easily.

Last change: 2024-04-11, commit: f978552

Preparing Your Environment

Prerequisites

  • Rust & cargo

Creating your Project Structure

  • Make a new cargo project:
cargo new nym-cosmos-service
  • Create the following directory structure and files:
.
├── Cargo.toml
├── bin
│   ├── client.rs
│   └── service.rs
└── src
    ├── client.rs
    ├── lib.rs
    └── service.rs

3 directories, 6 files
  • Add the following dependencies to your Cargo.toml file:
[dependencies]
clap = { version = "4.0", features = ["derive"] }
cosmrs = "=0.15.0"
tokio = { version = "1.24.1", features = ["rt-multi-thread", "macros"] }
serde = "1.0.152"
serde_json = "1.0.91"
anyhow = "1.0.72"

These are non Nym-specific dependencies for the project. clap is for setting up the CLI commands, cosmrs for cosmos-specific types and functionality, tokio for the async/await environment, and serde for (de)serialisation. anyhow is for catch-all error handling.

  • Next add Nym-specific dependencies. Since these libraries are not yet on crates io then you need to import them from the Nym monorepo:
nym-sdk = { git = "https://github.com/nymtech/nym", rev = "85a7ec9f02ca8262d47eebb6c3b19d832341b55d" }
nym-sphinx-addressing = { git = "https://github.com/nymtech/nym", rev = "85a7ec9f02ca8262d47eebb6c3b19d832341b55d" }
nym-validator-client = { git = "https://github.com/nymtech/nym", rev = "85a7ec9f02ca8262d47eebb6c3b19d832341b55d" }
nym-bin-common = { git = "https://github.com/nymtech/nym", rev = "85a7ec9f02ca8262d47eebb6c3b19d832341b55d" }
nym-sphinx-anonymous-replies = { git = "https://github.com/nymtech/nym", rev = "85a7ec9f02ca8262d47eebb6c3b19d832341b55d" }

The sphinx dependencies are for packet- and address-related functionality, the validator-client for Nyx blockchain specific configs, common for client logging, and the sdk for SDK functionality: creating and managing client storage and connections, and sending and receiving messages to and from the mixnet.

  • Finally add the following underneath your [dependencies]:
[[bin]]
name = "client"
path = "bin/client.rs"

[[bin]]
name = "service"
path = "bin/service.rs"

This defines multiple binaries to run in a single cargo project, as outlined here.

Last change: 2024-04-11, commit: f978552

Preparing Your Lib

Now move on to preparing shared data structures and functions in src/lib.rs.

These include the request and response types the client and the service will be passing through the mixnet, as well as shared functions such as client creation, and message parsing.

Dependencies

The dependencies for the shared lib file are the following:

#![allow(unused)]
fn main() {
use anyhow::bail;
use cosmrs::AccountId;
use nym_sdk::mixnet::{
    AnonymousSenderTag, MixnetClient, MixnetClientBuilder, ReconstructedMessage, StoragePaths,
};
use nym_validator_client::nyxd::Coin;
use serde::{Deserialize, Serialize};
use std::path::PathBuf;

pub mod client;
pub mod service;
}

Since this is the file where client creation and message parsing are handled, the various nym_sdk imports, as well as serde’s (de)serialisation functionality, are required. PathBuf is for reading filepaths, cosmrs types are required for defining Nyx blockchain accounts, and the Coin type from the nyxd_validator_client is for our Coin balance request and response. anyhow is for easy error handing.

Constants

Below this are the chain-related const variables. These have been hardcoded for this demo.

#![allow(unused)]
fn main() {
pub const DEFAULT_VALIDATOR_RPC: &str = "https://rpc.sandbox.nymtech.net";
pub const DEFAULT_DENOM: &str = "unym";
pub const DEFAULT_PREFIX: &str = "n";
}

These define the RPC endpoint your service will use to interact with the blockchain - in this case the Sandbox testnet - as well as the expected coin denomination, and Bech32-prefix of addresses.

Shared Data Structures

Define the following structs for our different request and responses that will be serialised and sent through the mixnet between your client and service binaries:

#![allow(unused)]
fn main() {
#[derive(Debug, Deserialize, Serialize, PartialEq)]
pub struct BalanceRequest {
    pub validator: String,
    pub account: AccountId,
}

#[derive(Debug, Deserialize, Serialize, PartialEq)]
pub struct BalanceResponse {
    pub balance: Coin,
}

#[derive(Debug, Deserialize, Serialize, PartialEq)]
pub enum RequestTypes {
    Balance(BalanceRequest),
}

impl RequestTypes {
    pub fn serialize(&self) -> Vec<u8> {
        serde_json::to_vec(self).expect("serde failure")
    }

    pub fn try_deserialize<M: AsRef<[u8]>>(raw: M) -> anyhow::Result<Self> {
        serde_json::from_slice(raw.as_ref()).map_err(Into::into)
    }
}

#[derive(Debug, Deserialize, Serialize, PartialEq)]
pub enum ResponseTypes {
    Balance(BalanceResponse),
}

impl ResponseTypes {
    pub fn serialize(&self) -> Vec<u8> {
        serde_json::to_vec(self).expect("serde failure")
    }

    pub fn try_deserialize<M: AsRef<[u8]>>(raw: M) -> anyhow::Result<Self> {
        serde_json::from_slice(raw.as_ref()).map_err(Into::into)
    }
}
}

The above data types are pretty straightforward. Even though there are only one instance of a request type (sent from client -> mixnet -> service) and one of a response type (service -> mixnet -> client) so far, a pair of enums has been defined to contain additional response and request types that will be added in part 2 of this tutorial, when adding credential functionality.

BalanceRequest will be used when requesting the service to query the token balance of the supplied address on the client’s behalf. You can see the information that will be returned from the chain to the service, and from the service to the client, in BalanceResponse.

Custom serialistion and deserialisation have been implemented for each enum for ease of future modification and testing.

Shared Functions

Now to define functions shared by the client and service binaries.

Client Creation

The following function is called on startup by each binary, with the config_path being a filepath for storing client config:

#![allow(unused)]
fn main() {
// create our client with specified path for key storage
pub async fn create_client(config_path: PathBuf) -> MixnetClient {
    let config_dir = config_path;
    let storage_paths = StoragePaths::new_from_dir(&config_dir).unwrap();
    let client = MixnetClientBuilder::new_with_default_storage(storage_paths)
        .await
        .unwrap()
        .build()
        .unwrap();

    client.connect_to_mixnet().await.unwrap()
}
}

If no config files exist at the location designated by config_path (in this case /tmp/service) then the following files are generated:

service
├── ack_key.pem
├── db.sqlite
├── db.sqlite-shm
├── db.sqlite-wal
├── gateway_details.json
├── gateway_shared.pem
├── persistent_reply_store.sqlite
├── private_encryption.pem
├── private_identity.pem
├── public_encryption.pem
└── public_identity.pem

1 directory, 11 files

If keys and config already exist at this location, re-running this function will not overwrite them.

Listening for & Parsing Incoming messages

Next to define two functions: one for listening for messages from the mixnet (used by service), and one for handling a response to a request (used by client).

Both functions attempt to deserialise the vec of ReconstructedMessages that are reconstructed by the client from delivered Sphinx packets after decryption.

handle_request performs one additional function - parsing the sender_tag from the incoming reconstructed message. This is the randomised alphanumeric string used to identify a bucket of SURBs (Single Use Reply Blocks) that are sent along with any outgoing message by default. More information about them can be found here but all that is necessary to know for now is that these are pre-addressed packets that clients send out with their messages. Any reply to their message that is to be sent back to them back be written to the payload of these packets, but without the replying party being able to see the destination that the reply is being sent to. This allows for services to anonymously reply to clients without being able to doxx them by knowing their Nym address.

#![allow(unused)]
fn main() {
pub fn handle_response(message: ReconstructedMessage) -> anyhow::Result<ResponseTypes> {
    ResponseTypes::try_deserialize(message.message)
}

pub fn handle_request(
    message: ReconstructedMessage,
) -> anyhow::Result<(RequestTypes, Option<AnonymousSenderTag>)> {
    let request = RequestTypes::try_deserialize(message.message)?;
    Ok((request, message.sender_tag))
}
}

Before moving on to the client and service code, one more function is needed. This allows for both binaries to parse empty incoming messages that they might receive. This is necessary as incoming SURBs, as well as requests for more SURBs, contain empty data fields.

#![allow(unused)]
fn main() {
pub async fn wait_for_non_empty_message(
    client: &mut MixnetClient,
) -> anyhow::Result<ReconstructedMessage> {
    while let Some(mut new_message) = client.wait_for_messages().await {
        if !new_message.is_empty() {
            return Ok(new_message.pop().unwrap());
        }
    }

    bail!("did not receive any non-empty message")
}
}
Last change: 2024-04-11, commit: f978552

Preparing Your Client

Start by creating the startup logic of your client in bin/client.rs - creating a Nym client and connecting to the mixnet (or just connecting if your client has been started before and config already exists for it), and defining and running commands.

Dependencies

Import the following dependencies:

#![allow(unused)]
fn main() {
use clap::{Args, Parser, Subcommand};
use chain_query::{client::query_balance, create_client};
use nym_sdk::mixnet::Recipient;
use nym_validator_client::nyxd::AccountId;
use nym_bin_common::logging::setup_logging;
}

clap is used so different commands can be passed to the client (even though we’re only defining one function in this first part of the tutorial, more will be added in subsequent chapters). nym_sdk::mixnet::Recipient is the type used to define the recipient of a mixnet message, nym_bin_common::logging::setup_logging is the logging setup for client’s Nym client, and chain_query imports the create_client and query_balance functions created on the previous page.

CLI Command with Clap

The following simply defines the commands that the client can perform. For the moment, there is only one: the query_balance function created in the previous section.

As with the data structures, this structure is being used for ease of adding future commands in subsequent tutorials.

#![allow(unused)]
fn main() {
#[derive(Debug, Parser)]
#[clap(name = "rust sdk demo - chain query service")]
#[clap(about = "query the sandbox testnet blockchain via the mixnet... part 2 coming soon")]
struct Cli {
    #[clap(subcommand)]
    command: Option<Commands>,
}

#[derive(Debug, Subcommand)]
enum Commands {
    QueryBalance(QueryBalance),
}

#[derive(Debug, Args)]
struct QueryBalance {
    /// the account we want to query
    account: AccountId,
    /// the address of the broadcaster service - this submits txs and queries the chain on our behalf
    sp_address: String,
}
}

main()

This is the root logic of the client. Using [tokio](https://tokio.rs/) for the async runtime, this function performs the following functions:

  • If not already existing, create a Nym client with config at /tmp/client. Otherwise load the already existing client from this config.
  • Matche the command from the CLI - in this instance, the QueryBalance function which will be defined in the next section. This creates a BalanceRequest and sends this to the service, before returning the response back to the main thread and print this to the console.
  • Perform a proper shutdown of the Nym client.
#[tokio::main]
async fn main() -> anyhow::Result<()> {
    setup_logging();
    let cli = Cli::parse();
    let mut client = create_client("/tmp/client2".into()).await;
    let our_address = client.nym_address();
    println!("\nclient's nym address: {our_address}");

    match cli.command {
        Some(Commands::QueryBalance(QueryBalance {
            account,
            sp_address,
        })) => {
            println!("\nsending bank balance request to service via mixnet");
            let sp_address = Recipient::try_from_base58_string(sp_address).unwrap();
            let returned_balance = query_balance(account, &mut client, sp_address).await?;
            println!("\nreturned balance is: {}", returned_balance);
        }
        None => {
            println!("\nno command specified - nothing to do")
        }
    }
    println!("\ndisconnecting client");
    client.disconnect().await;
    println!("client disconnected");
    Ok(())
}
Last change: 2024-04-11, commit: f978552

Preparing Your Client pt2

Open src/client.rs. This is where the logic of the command from the match statement in bin/client.rs is defined.

Dependencies

#![allow(unused)]
fn main() {
use crate::{handle_response, wait_for_non_empty_message, RequestTypes, DEFAULT_VALIDATOR_RPC};
use cosmrs::AccountId;
use nym_sdk::mixnet::MixnetClient;
use nym_sphinx_addressing::clients::Recipient;
use nym_validator_client::nyxd::Coin;
}

As well as importing message-handling functionality, request types, and the default RPC endpoint, this file relies on the AccountId type to construct blockchain addresses, the MixnetClient for interacting with the mixnet, the Recipient type to construct mixnet recipient addresses, and the Coin type for properly handling the returned balance of the account that will be queried.

Querying via the Mixnet

The following is used to construct a BalanceRequest, send this to the supplied service address, and then handle the response, matching it to a ResponseType (in this case the only expected response, a BalanceResponse).

The actual sending of the request is performed by client.send_message: sending the serialised BalanceRequest to the supplied Nym address (the Recipient imported from the nym_sphinx_addressing crate). It is sending the default number of SURBs along with the message as the third argument, defined here.

#![allow(unused)]
fn main() {
pub async fn query_balance(
    account: AccountId,
    client: &mut MixnetClient,
    sp_address: Recipient,
) -> anyhow::Result<Coin> {
    // construct balance request
    let message = RequestTypes::Balance(crate::BalanceRequest {
        validator: DEFAULT_VALIDATOR_RPC.to_owned(), // rpc endpoint for broadcaster to use
        account,
    });

    // send serialised request to service via mixnet
    let _ = client
        .send_message(sp_address, message.serialize(), Default::default())
        .await;

    let received = wait_for_non_empty_message(client).await?;

    // listen for response from service
    let sp_response = handle_response(received)?;

    // match JSON -> ResponseType
    let res = match sp_response {
        crate::ResponseTypes::Balance(response) => {
            println!("{:#?}", response);
            response.balance
        }
    };

    Ok(res)
}
}

That is all the client code written: now to move on to the service that will be interacting with the blockchain on behalf of the client.

Last change: 2024-04-11, commit: f978552

Preparing Your Service

In bin/src.rs define the startup and response logic of the service. Client connection / config reading happens as it does in bin/client.rs.

Dependencies

#![allow(unused)]
fn main() {
use chain_query::{
    create_client, handle_request,
    service::{create_broadcaster, get_balance},
    BalanceResponse, RequestTypes, ResponseTypes,
};
use nym_sphinx_anonymous_replies::{self, requests::AnonymousSenderTag};
use nym_bin_common::logging::setup_logging;
use nym_sdk::mixnet::MixnetMessageSender;
}

The imports from chain_query are most of the data types and functions defined in the previous sections of this tutorial.

The AnonymousSenderTag type is used for SURBs.

main()

Also using tokio for the async runtime, main does the following:

  • Create a Nym client with config at /tmp/service, or load the existing client from this config directory.
  • Create a broadcaster - this is used by the service to interact with the blockchain, using the consts defined in src/lib.rs as chain config.
  • Listen out for incoming messages, and in much the same way as the client, handle and match the incoming request.
  • Using the sender_tag, anonymously reply to the client with the response from the blockchain without having to know the client’s Nym address.
#[tokio::main]
async fn main() -> anyhow::Result<()> {
    setup_logging();
    let mut client = create_client("/tmp/service".into()).await;
    let our_address = client.nym_address();
    println!("\nservice's nym address: {our_address}");
    // the httpclient we will use to broadcast our query to the blockchain
    let broadcaster = create_broadcaster().await?;
    println!("listening for messages, press CTRL-C to exit");

    while let Some(received) = client.wait_for_messages().await {
        for msg in received {
            let request = match handle_request(msg) {
                Ok(request) => request,
                Err(err) => {
                    eprintln!("failed to handle received request: {err}");
                    continue;
                }
            };

            let return_recipient: AnonymousSenderTag = request.1.expect("no sender tag received");
            match request.0 {
                RequestTypes::Balance(request) => {
                    println!("\nincoming balance request for: {}\n", request.account);

                    let balance: BalanceResponse =
                        get_balance(broadcaster.clone(), request.account).await?;

                    let response = ResponseTypes::Balance(balance);

                    println!("response from chain: {:#?}", response);

                    println!("\nreturn recipient surb bucket: {}", &return_recipient);
                    println!("\nsending response to {}", &return_recipient);
                    // send response back to anon requesting client via mixnet
                    let _ = client
                        .send_reply(return_recipient, &serde_json::to_string(&response)?)
                        .await;
                }
            }
        }
    }

    Ok(())
Last change: 2024-04-11, commit: f978552

Preparing Your Service pt2

Now to define the logic of creating the broadcaster for interacting with the blockchain, and querying it in src/service.rs.

Dependencies

The following dependencies are for creating a client to interact with the blockchain, and deal with the returned Coin type in BalanceResponse.

#![allow(unused)]
fn main() {
use crate::{BalanceResponse, DEFAULT_DENOM, DEFAULT_VALIDATOR_RPC};
use cosmrs::rpc::HttpClient;
use cosmrs::AccountId;
use nym_validator_client::nyxd::{Coin, CosmWasmClient};
}

Creating a broadcaster

The broadcaster is an HttpClient taken from cosmrs, created with the DEFAULT_VALIDATOR_RPC as its default endpoint. The service will use this to query the Sandbox testnet chain.

#![allow(unused)]
fn main() {
pub async fn create_broadcaster() -> anyhow::Result<HttpClient> {
    let broadcaster: HttpClient = HttpClient::new(DEFAULT_VALIDATOR_RPC)?;
    Ok(broadcaster)
}
}

Querying the Chain

Now to write the logic for querying the chain, using the broadcaster created in the previous step to query for the balance of the account that the client sent via the mixnet in the BalanceRequest. This function returns a BalanceResponse containing a Coin type, denoting the balance and denom returned by get_balance().

#![allow(unused)]
fn main() {
pub async fn get_balance(
    broadcaster: HttpClient,
    account: AccountId,
) -> anyhow::Result<BalanceResponse> {
    let balance = broadcaster
        .get_balance(&account, DEFAULT_DENOM.to_string())
        .await
        .unwrap()
        .unwrap();
    Ok(BalanceResponse {
        balance: Coin {
            amount: balance.amount,
            denom: balance.denom,
        }, 
    })
}
}
Last change: 2024-04-11, commit: f978552

Querying the Chain

Now that all the code has been written, time to query the blockchain.

To test against the account operating one of the mix nodes on the testnet, use n1lcutqz94k739s39u26rvexql40ehf42zd27fwe in the following instructions:

# build the binaries
cargo build --release

# open two console windows. In one run the following
./target/release/service

# copy the printed Nym address from the console - this is used by the client when running the chain query

# in the other run
./target/release/client query-balance n1lcutqz94k739s39u26rvexql40ehf42zd27fwe <SERVICE_ADDRESS_FROM_CLIPBOARD>

The following happens:

  • client and service both start their Nym clients and log the address. service is listening for incoming messages from the mixnet.
  • client sends a request to service using the supplied n1... address as the Nyx account to query the balance of, and the supplied Nym address to communicate with this instance of service.
  • service queries the Sandbox testnet blockchain using the broadcaster http client. It then serialises the response and returns it using SURBs to the client.

All in all, quite simple. By using the service as a proxy, the client never interacts with the blockchain, thus is not revealing metadata to the operator of the Validator nor any entities monitoring its incoming and outgoing traffic. Furthermore, the client doesn’t even need to share its Nym address with the service, as the service is able to reply via SURBs.

Creating Sandbox Account

If you wish to create an account on Sandbox to use instead of the supplied account above, the easiest way is by building the nym-cli tool and using that to create one:

# start from the root of the nym monorepo
cd tools/nym-cli
# build
cargo build --release
# create account using Sandbox testnet environment
../../target/release/nym-cli --config-env-file ../../envs/sandbox.env account create

However, since this account is fresh, it won’t have any tokens. Querying the balance will still work obviously, it will just return 0.

Get Tokens

We’re working on getting the faucet up and running again in preparation for part 2 of this tutorial: using the tokens you have privately checked the balance of to generate a bandwidth credential.

If you wish to get testnet tokens already then feel free to ask in the Dev channel on Matrix.

Last change: 2024-04-11, commit: f978552

Typescript

Tutorial code in this section is built to interact with a standalone Nym client. You can read about interacting with standalone clients here, although it is usually preferable to use the Typescript SDK.

Last change: 2024-04-11, commit: f978552

Building a Simple Service Provider

Warning

This tutorial was written before the creation of the Typescript SDK, and involves running a Nym Client alongside your application processes, instead of relying on the SDK to integrate the Client process into your application logic.

As such, although this tutorial is still a valid way of approaching building on Nym, it is a little less streamlined than it could be.

A more streamlined rewrite of this tutorial will be coming soon.

This tutorial is the best place to start for developers new to Nym. You will learn how to build a minimum viable privacy-enabled application (PEApp) able to send and receive traffic via the mixnet.

This tutorial is less about building an immediately useful application, and more about beginning to understand:

  • Sending messages through the mixnet to another Nym client
  • Receiving messages from the mixnet and handling them
  • Anonymous replies with Single Use Reply Blocks (SURBs)

That said, this tutorial will give you the skeleton of an application, onto which you can add more useful functionality.

Last change: 2024-04-11, commit: f978552

Tutorial Overview

Components Created in this Tutorial

This tutorial involves writing two pieces of code in Typescript:

  • A User Client (UC) with which you can access the mixnet through a browser on your local machine. You will use this to communicate with the second component outlined below.
  • A Service Provider (SP) which can communicate with the UC via the mixnet.

Additionally you will learn how to configure a pair of Nym Websocket Clients which both components use to connect to and communicate with the Mixnet.

SPs usually run on remote servers to assure reliable uptime and to unlink sender and receiver metadata. For demonstration purposes however, you will run both components on your local machine, looping messages through the mixnet to yourself.

       +----------+              +----------+             +----------+ 
       | Mix Node |<-----------> | Mix Node |<----------->| Mix Node |
       | Layer 1  |              | Layer 2  |             | Layer 3  |
       +----------+              +----------+             +----------+  
            ^                                                   ^      
            |                                                   |      
            |<--------------------------------------------------+
            |                                                          
            v                                                        
    +--------------+                                
    | Your gateway |                               
    +--------------+                               
            ^                                       
            |                                                                      
            |                                                                         
            v                                                        
+-------------------------------------------+                         
|                                           |                        
|  +------------+     +------------+        |                      
|  | Nym Client |     | Nym Client |        |                     
|  +------------+     +------------+        |                    
|        ^                  ^               |                   
|        |                  |               |                  
|        |                  |               |                 
|        v                  v               |                
|  +-------------+    +------------------+  |               
|  | User Client |    | Service Provider |  |              
|  +-------------+    +------------------+  |             
|                                           |            
+-------------------------------------------+           
            Your Local Machine          

Aims of this Tutorial

  • Create a user-friendly experience for sending data through the mixnet via a simple form accessible through a web browser.
  • Configure and use a pair of Nym Websocket Clients.
  • Send a properly formatted message through the mixnet to the SP from a browser-based GUI.

You can find the code for these components here. You can use it as a reference while building or simply download it and follow along as you progress through the tutorial.

Notice that this tutorial attempts to use very few external libraries (the User Client codebase is basically vanilla Typescript!). This tutorial is not showing you how to build production-grade code, but to understand how to connect and send messages to, as well as recieve messages from, the mixnet.

Sidenote: What is a Service Provider?

‘Service Provider’ is a catchall name used to refer to any type of app that can communicate with the mixnet via a Nym client.

The first SP to have been released is the Network Requester - a binary that receives a network request from the mixnet, performs that request (e.g. authenticating with a message server and receiving new messages for a user) and then passes the response back to the user who requested it anonymously, shielding their metadata from the message server.

The SP you will build in this tutorial is far more simple than this. It is just to show you how to approach building something that can:

  • connect to the mixnet,
  • listen for messages, and
  • perform some action with them (in this case, log them in a console and reply to the original sender).

However, once you see how easy it is to integrate with the mixnet for traffic transport, you will be able to build apps with real-world uses easily.

Last change: 2024-04-11, commit: f978552

Preparing Your User Client Environment

Prerequisites

  • NodeJS & npm
  • typescript

Preparing your TypeScript environment

  • Make a new directory called simple-service-provider-tutorial containing a directory named user-client:
mkdir -p simple-service-provider/user-client
  • Create a package.json and install dependencies:
cd simple-service-provider/user-client 
npm init  
npm install typescript # allows you to write and use typescript 
npm install ts-node --save-dev # allows you to build a typescript application in a NodeJS environment 
  • Create a tsconfig.json containing the following:
{
    "compilerOptions": {
        "module": "commonjs",
        "esModuleInterop": true,
        "target": "es6",
        "moduleResolution": "node",
        "sourceMap": true,
        "outDir": "dist"
    },
    "lib": ["es2015"]
}

Preparing your Bundler

  • We will use the Parcel bundler to build and run our app locally. Parcel also supports hot reloading, making for a nicer developer experience when working on our app. Install it with:
npm install parcel-bundler
  • Create the file structure for our frontend code:
mkdir src 
touch src/index.html src/index.ts

At this point your directory should look like this (check yourself with tree -L 2 simple-service-provider/):

simple-service-provider/
└── user-client
    ├── node_modules
    ├── package.json
    ├── package-lock.json
    ├── src
    └── tsconfig.json

4 directories, 3 files

And user-client/src/ should look like this:

user-client/src
├── index.html
└── index.ts

1 directory, 2 files
  • Time to check everything is working. Paste the following into src/index.html:
<!DOCTYPE html>
<html>
    <head>
        <title>App Test</title>
        <meta charset="utf-8"/>
    </head>
    <body>
        <h1>Test</h1>
        <div id="app"></div>
        <script src="index.ts"></script>
    </body>
</html>
  • Paste the following into src/index.ts
console.log('test log')
  • Add the following to package.json in the "scripts" array, above "test":
"start": "parcel src/index.html"
  • npm start should return:
> user-client@1.0.0 start
> parcel src/index.html

Server running at http://localhost:1234
✨  Built in 1.57s.

Open localhost:1234 in your browser. Your web application should be up and running, with Test displayed in the browser window. Checking the console.log output is done by right-clicking on the browser and selecting Inspect, then navigating to the Console section of the resulting panel. You should see the message test log displayed there.

Last change: 2024-04-11, commit: f978552

Building Your User Client

Adding Core Functionality

Most of the work here will be configuring and adding functionality to src/index.ts file, allowing you to establish and handle the websocket connection to your local Nym client, and create and send messages to the SP.

  • Replace the existing content of src/index.ts with:
async function main() {}

function connectWebsocket(url) {
    return new Promise(function (resolve, reject) {
        var server = new WebSocket(url);
        console.log('connecting to Websocket Server (Nym Client)...')
        server.onopen = function () {
            resolve(server);
        };
        server.onerror = function (err) {
            reject(err);
        };
      
    });
}
    
main();

main() will the majority of the app’s logic. It’s best to declare it at the start of the file and call it at the end to run when launching the application.

connectWebsocket(url) returns a Promise that attempts to create a websocket connection to url. If the connection is successful, you will get a notification in your running application in the browser, as well as the connected Nym client. If it fails an error will be displayed in the browser.

  • Now to implement the functions that will handle DOM (Document Object Model) manipulation. Add the following below connectWebsocket():
function handleResponse(resp) {
    try {
        let response = JSON.parse(resp.data);
        if (response.type == "error") {
            displayJsonResponse("Server responded with error: " + response.message);
        } else if (response.type == "selfAddress") {
            ourAddress = response.address;
            displayClientMessage("Our address is:  " + ourAddress + ", we will now send messages to ourself.");
        } else if (response.type == "received") {
            handleReceivedTextMessage(response)
        }
    } catch (_) {
            displayJsonResponse(resp.data)
    }
}
       
function handleReceivedTextMessage(message) {
    const text = JSON.parse(message.message);
    displayJsonResponse(text);
}
        
// Display websocket responses in the Activity Log.
function displayJsonResponse(message) {
    let receivedDiv = document.createElement("div")
    let paragraph = document.createElement("p")
    paragraph.setAttribute('style', 'color: orange')
    let textNode = document.createTextNode("received >>> " + message.text)
    paragraph.appendChild(textNode)
    
    receivedDiv.appendChild(paragraph)
    document.getElementById("output").appendChild(receivedDiv)
}

function displayClientMessage(message) {
    document.getElementById("output").innerHTML += "<p>" + message + "</p >";
}

handleResponse() parses the type of any messages received from the websocket, and handles forwarding the message on to the appropriate function depending on this type. You can find documentation on these types here.

handleReceivedTextMessage() ensures that data is json data before displaying on the UI.

displayJsonResponse() is responsible for displaying received messages on the UI, creating a new <p> HTML element for each message that needs to be displayed on screen.

displayClientMessage() displays the address of the connected Nym client.

  • Declare the following variables above main()
var ourAddress:          string;
var targetAddress:       string;
var websocketConnection: any;

ourAddress takes the value of the connected Nym client address.

targetAddress will be the Nym address of the SP.

websocketConnection populated upon a successful response from connectWebsocket().

  • Add the following to main():
async function main() {
    var port = '1977' // Nym Websocket Client listens on 1977 by default.
    var localClientUrl = "ws://127.0.0.1:" + port;
    
    // Set up and handle websocket connection to our desktop client.
    websocketConnection = await connectWebsocket(localClientUrl).then(function (c) {
        return c;
    }).catch(function (err) {
        displayClientMessage("Websocket connection error. Is the client running with <pre>--connection-type WebSocket</pre> on port " + port + "?");
    })

    websocketConnection.onmessage = function (e) {
        handleResponse(e);
    };
    
    sendSelfAddressRequest();
    
    // Set up the send button
    const sendButton = document.querySelector('#send-button');
    
    sendButton?.addEventListener('click', function handleClick(event) {
        sendMessageToMixnet(); 
    });

And between main() and displayClientMessage():

function sendSelfAddressRequest() {
    var selfAddress = {
        type: "selfAddress"
    }
    displayJsonSend(selfAddress);
    websocketConnection.send(JSON.stringify(selfAddress));
}

sendSelfAddressRequest() sends a selfAddress message to the connected websocket client, passing the response to displayJsonSend() to be displayed on your UI.

main() now contains logic for: connecting to a local Nym client, getting its address with a selfAddress message, and displaying it on the UI. Now your app can display its connection status, letting you know whether it is(n’t) connected to a running client!

  • Underneath sendSelfAddressRequest() implement a function to send messages down the websocket connection to the SP:
function sendMessageToMixnet() {

    var nameInput = (<HTMLInputElement>document.getElementById("nameInput")).value;
    var textInput = (<HTMLInputElement>document.getElementById("textInput")).value;
   
    const messageContentToSend = {
        name : nameInput,
        comment : textInput,
    }
    
    const message = {
        type: "sendAnonymous",
        message: JSON.stringify(messageContentToSend),
        recipient: targetAddress,
        replySurbs: 5
    }
    
    displayJsonSend(message);
    websocketConnection.send(JSON.stringify(message));
}

Nym clients accept messages in either binary or JSON formats. Since you are sending JSON data, you need to stringify any messages you wish to send through the mixnet.

You are sending replySURBs along with the message to the SP. This allows the SP to reply to you without you having to doxx yourself and supply a ‘return address’ in a readable form to it. TLDR; SURBs allow for anonymous replies from mixnet services!

  • Below sendMessageToMixnet(), add the following:
function displayJsonSend(message) {
    let sendDiv = document.createElement("div")
    let paragraph = document.createElement("p")
    paragraph.setAttribute('style', 'color: #36d481')
    let paragraphContent = document.createTextNode("sent >>> " + JSON.stringify(message))
    paragraph.appendChild(paragraphContent)
            
    sendDiv.appendChild(paragraph)
    document.getElementById("output").appendChild(sendDiv)
}

displayJsonSend() displays sent messages in the “Activity Log” section of the UI.

  • Replace the contents of src/index.html with the following:
<!doctype html>
<html>
    <head>
        <meta charset="UTF-8">
        <title>Mixnet Websocket Starter Client</title>
        <link rel="stylesheet" href="../assets/styles.css"/>
    </head>
    <body>
        <div class="content" role="main">
            <div class="toolbar">
                <h3>Mixnet Websocket Starter User Client</h3>
            </div>
            
            <div class="section-container">
               
                <label for="nameInput" class="form-field-label">Moniker</label>
                <input id="nameInput" type="text" value="An0n" name="nameInput">

                <label for="textInput" class="form-field-label">Comment</label>
                <input id="textInput" type="text" value="I would like to use your private service" name="textInput">
         
                <div id="send-button">
                    <label for="send-button" class="submit-button">Send</label>
                </div>
            </div>
        </div>
        
        <div class="" style="margin-left:20px;max-width: fit-content;">
            <div style="color: white;margin-bottom: 2rem;">
                <h4>How it works</h4>
                <p>Once you have started your Nym Websocket client, you can fill out the form and send data to the Service Provider via mixnet using the <b>"Send"</b> button.</p>
                <p>Below, you can see the activity log. <b style='color: #36d481;'>Sent</b> messages will display in <b style='color: #36d481;'>green</b> while <b style='color: orange;'>received</b> messages will display in <b style='color: orange;'>orange</b>.</p>
            </div>
        </div>
        
        <h3 style="margin-left:10px">Activity Log</h3>
        
        <p class="output-container">
            <span id="output"></div>
        </p>
        <script src="index.ts"></script>
    </body>
</html>

Lets add the finishing touches to the UI by adding in the stylesheet which we specified at the top of index.html:

mkdir -p assets
touch assets/styles.css

# grab the stylesheet from the remote repo and save it to the newly created css file
curl https://raw.githubusercontent.com/nymtech/developer-tutorials/main/simple-service-provider-tutorial/user-client/assets/styles.css -o assets/styles.css
  • Return back to your terminal and run:
npm start

Return to localhost:1234) and you should see an updated UI.

Connecting to your Nym Client

Follow instructions in the Nym websocket client documentationto init and run a client then refresh your browser window. You should see a successful response, including a Nym address, in the ‘Activity Log’ of the UI

Your User Client application code is connected to a Nym websocket client, and ready to send messages through the mixnet!

In the next section, you will build the Service application you will send these messages to.

Last change: 2024-04-11, commit: f978552

Preparing Your Service Provider Environment

  • Now to move on to prepare our development environment for the Service Provider code. Create a directory for it:
# run this from the root of `simple-service-provider/`
mkdir service-provider
cd service-provider
  • Create a package.json:
npm init
  • Inside your newly generated package.json, paste in the following code:
{
    "name": "service-provider",
    "version": "1.0.0",
    "description": "",
    "main": "index.js",
    "scripts": {
        "start:dev": "nodemon",
        "test": "echo \"Error: no test specified\" && exit 1"
    },
    "devDependencies": {
        "@types/node": "^18.14.0",
        "@types/ws": "^8.5.4",
        "nodemon": "^2.0.20",
        "ts-node": "^10.9.1",
        "typescript": "^4.8.4"
    },
    "author": "",
    "license": "ISC",
    "dependencies": {
        "ws": "^8.12.0"
    }
}
  • install dependecies:
npm install
  • create a tsconfig.json file containing the following:
{
    "compilerOptions": {
    "target": "es2017", 
    "lib": [
        "es6"
    ],
    "module": "Node16", 
    "rootDir": "src", 
    "resolveJsonModule": true, 
    "allowJs": true,                      
    "outDir": "build", 
    "esModuleInterop": true, 
    "forceConsistentCasingInFileNames": true, 
    "strict": true, 
    "noImplicitAny": true, 
    "skipLibCheck": true 
    }
}
  • You will use Nodemon to reload your app on code changes. Create a nodemon.json file in the same directory which will act as our nodemon configuration. Paste in the following code inside that file:
{
    "watch": [
        "src"
    ],
    "ext": ".ts,.js",
    "ignore": [],
    "exec": "ts-node ./src/index.ts"
}
  • Finally, create a typescript file for our app logic:
mkdir src
touch src/index.ts

At this point your directory should look like this (check yourself with tree -L 2 simple-service-provider):

simple-service-provider
├── service-provider
│   ├── node_modules
│   ├── nodemon.json
│   ├── package.json
│   ├── package-lock.json
│   ├── src
│   └── tsconfig.json
└── user-client
    ├── node_modules
    ├── package.json
    ├── package-lock.json
    ├── src
    └── tsconfig.json

7 directories, 7 files

And service-provider/src/ should look like this:

service-provider/src
└── index.ts

1 directory, 1 file
Last change: 2024-04-11, commit: f978552

Building Your Service Provider

Since a lot of logic you will write in this section is similar or the same to UC code you just written, this section will only focus on SP-specific functionality

  • Paste the following code into src/index.ts
import WebSocket, { MessageEvent } from "ws";

var ourAddress:          string;
var websocketConnection: any;

async function main() {
    var port = '1978' 
    var localClientUrl = "ws://127.0.0.1:" + port;

    // Set up and handle websocket connection to our desktop client.
    websocketConnection = await connectWebsocket(localClientUrl).then(function (c) {
        return c;
    }).catch(function (err) {
        console.log("Websocket connection error. Is the client running with <pre>--connection-type WebSocket</pre> on port " + port + "?");
        console.log(err);
    })

    websocketConnection.onmessage = function (e : any) {
        handleResponse(e);
    };

    sendSelfAddressRequest();
}

// Handle any messages that come back down the websocket. 
function handleResponse(responseMessageEvent : MessageEvent) {

    try {
            let response = JSON.parse(responseMessageEvent.data.toString());
        if (response.type == "error") {
            console.log("\x1b[91mAn error occured: " + response.message + "\x1b[0m")
        } else if (response.type == "selfAddress") {
            ourAddress = response.address;
            console.log("\x1b[94mOur address is: " + ourAddress + "\x1b[0m")
        } else if (response.type == "received") {
            let messageContent = JSON.parse(response.message)

            console.log('\x1b[93mRecieved : \x1b[0m');
            console.log('\x1b[92mName : ' + messageContent.name + '\x1b[0m');
            console.log('\x1b[92mService : ' + messageContent.service + '\x1b[0m');
            console.log('\x1b[92mComment : ' + messageContent.comment + '\x1b[0m');

            console.log('\x1b[93mSending response back to client... \x1b[0m')

	    sendMessageToMixnet(response.senderTag)
        }
    } catch (_) {
        console.log('something went wrong in handleResponse')
    }
}

function sendMessageToMixnet(senderTag: string) {

    // Place each of the form values into a single object to be sent.
    const messageContentToSend = {
        text: 'We recieved your request - this reply sent to you anonymously with SURBs',
        fromAddress : ourAddress
    }
    
    const message = {
        type: "reply",
        message: JSON.stringify(messageContentToSend),
    	senderTag: senderTag
    }
    
    // Send our message object via out via our websocket connection.
    websocketConnection.send(JSON.stringify(message));
}

// Send a message to the mixnet client, asking what our own address is. 
function sendSelfAddressRequest() {
    var selfAddress = {
        type: "selfAddress"
    }
    websocketConnection.send(JSON.stringify(selfAddress));
}

// Function that connects our application to the mixnet Websocket. We want to call this first in our main function.
function connectWebsocket(url : string) {
    return new Promise(function (resolve, reject) {
        var server = new WebSocket(url);
        console.log('connecting to Mixnet Websocket (Nym Client)...')
        server.onopen = function () {
            resolve(server);
        };
        server.onerror = function (err) {
            reject(err);
        };

    });
}

main();

main() is still the function in charge of initializing and executing your application. Note that the SP’s client is running on port 1978. This is so we don’t have a conflict with the client we have running for the UC part of our tutorial code!

handleResponse() works in a similar manner as the function with the same name in simple-service-provider/user-client/src/index.ts. This implementation logs to the console instead of passing messages to a UI.

The \x1b prefix you see in console.log adds colour to console ouput. The number that you see following the [ and preceeding m is the colour code that can be compared here. Its a nice and quick way of styling our terminal output.

When the SP receives a message from the mixnet, sendMessageToMixnet() sends a response back to notify the the user that the SP recieved their request successfully.

Connecting to your Nym Client

Remember to init and run this client using port 1978 to avoid port clashes.

  • Refresh your browser window. You should see a successful response, including a Nym address, in your console:
> service-provider@1.0.0 start:dev
> nodemon

[nodemon] 2.0.20
[nodemon] to restart at any time, enter `rs`
[nodemon] watching path(s): src/**/*
[nodemon] watching extensions: ts,js
[nodemon] starting `ts-node ./src/index.ts`
connecting to Mixnet Websocket (Nym Client)...
Our address is: 6V5eEguz4rUsfntVLKQuD2ymgdY5iDKCV2GY2EH3CxG4.AKdk22atwRaVkN2PLEDsWUKKDc3ieNm1avKqVGgmJx8s@FQon7UwF5knbUr2jf6jHhmNLbJnMreck1eUcVH59kxYE

Set Service Address in User Client

The final step of this tutorial is to update our User Client code with the address of the now-running Service Provider so it can send it a message.

Copy the SP’s Nym address from your console and set it as the value of the targetAddress variable on line 2 of simple-service-provider/user-client/src/index.ts.

var targetAddress: string = '6V5eEguz4rUsfntVLKQuD2ymgdY5iDKCV2GY2EH3CxG4.AKdk22atwRaVkN2PLEDsWUKKDc3ieNm1avKqVGgmJx8s@FQon7UwF5knbUr2jf6jHhmNLbJnMreck1eUcVH59kxYE';
Last change: 2024-04-11, commit: f978552

Sending a Message Through the Mixnet

You are now ready to send a message through the mixnet!

You should have the following set up:

  • A User Client Web App
  • A Service Provider backend service
  • 2 Nym websocket clients, one for each component above

Simply fill in the fields in your browser and click Send. In your browser you will see the message sent to the SP, followed by the response from the SP. In your console you will see the logged incoming message from the UC, and the reply message to itfrom the SP.

This small project can be used as a template to start conceptualizing and developing more complex PEApps. Stay tuned for more soon, and if you’re searching for inspiration check out the community apps list!

Last change: 2024-04-11, commit: f978552

Web3 Privacy Now - Nym for Ethereum validator privacy

Serinko’s presentation on Web3Privacy Now: Community 1st introduces why network privacy matters for ETH 2.0 validators’ security and decentralisation.

This page serves as an accessible list of references mentioned during the talk.

References

Mixnet architecture

Nym <> ETH 2.0

Rust Examples

Clients

Nym Docs

Last change: 2024-04-11, commit: f978552

HCPP 2023 - Securing the Lunarpunks Workshop

Serinko’s workshop will introduce why and how to use Nym platform as a network protection layer when using some of our favorite privacy applications. This page serves as an accessible guide alongside the talk and it includes all the steps, pre-requisities and dependencies needed. Preferably the users interested in this setup start downloading and building the tools before the workshop or in the beginning of it. We can use the limited time for questions and addressing problems. This guide will stay online after the event just in case people were not finished and want to catch up later.

This page is a how to guide so it contains the setup only, to see the entire presentation join in at HCPP 2023 on Sunday.

Preparation

During this workshop we will introduce NymConnect and Socks5 client. The difference between them is that the Socks5 client does everything Nymconnect does, but it has more optionality and it’s run from a commandline. NymConnect is a one-button GUI application that wraps around the nym-socks5-client for proxying application traffic through the Mixnet.

We will learn how to run through Nym Mixnet the following applications: Electrum Bitcoin wallet, Monero wallet (desktop and CLI), Matrix (Element app) and ircd chat. For those who want to run ircd through the Mixnet, nym-socks5-client client is a must. For all other applications you can choose if you settle with our slick app NymConnect which does all the job in the background or you prefer Socks5 client.

Any syntax in <> brackets is a user’s/version unique variable. Exchange with a corresponding name without the <> brackets.

NymConnect Installation

NymConnect application is for everyone who does not want to install and run nym-socks5-client. NymConnect is plug-and-play, fast and easy use. Electrum Bitcoin wallet, Monero wallet (desktop and CLI) and Matrix (Element app) connects through NymConnect automatically to the Mixnet.

  1. Download NymConnect
  2. On Linux and Mac, make executable by opening terminal in the same directory and run:
chmod +x ./nym-connect_<VERSION>.AppImage
  1. Start the application
  2. Click on Connect button to initialise the connection with the Mixnet
  3. Anytime you’ll need to setup Host and Port in your applications, click on IP and Port to copy the values to clipboard
  4. In case you have problems such as Gateway Issues, try to reconnect or restart the application

Connect Privacy Enhanced Applications (PEApps)

For simplification in this guide we connect Electrum, Monero wallet and Matrix (Element) using NymConnect and ircd over nym-socks5-client. Of course if your choice is to run nym-socks5-client all these apps will connect through that and you don’t need to install NymConnect.

Info

This guide aims to connect your favourite applications to Nym Mixnet, therefore we do not include detailed guides on how to install them, only reference to the source pages.

Electrum Bitcoin wallet via NymConnect

To download Electrum visit the official webpage. To connect to the Mixnet follow these steps:

  1. Start and connect NymConnect (or nym-socks5-client)
  2. Start your Electrum Bitcoin wallet
  3. Go to: Tools -> Network -> Proxy
  4. Set Use proxy to ✅, choose SOCKS5 from the drop-down and add the values from your NymConnect application
  5. Now your Electrum Bitcoin wallet runs through the Mixnet and it will be connected only if your NymConnect or nym-socks5-client are connected.

Electrum Bitcoin wallet setup

Monero wallet via NymConnect

To download Monero wallet visit getmonero.org. To connect to the Mixnet follow these steps:

  1. Start and connect NymConnect (or nym-socks5-client)
  2. Start your Monero wallet
  3. Go to: Settings -> Interface -> Socks5 proxy -> Add values: IP address 127.0.0.1, Port 1080 (the values copied from NymConnect)
  4. Now your Monero wallet runs through the Mixnet and it will be connected only if your NymConnect or nym-socks5-client are connected.

Monero wallet setup

If you prefer to run Monero-CLI wallet with Monerod, please check out this guide.

Matrix (Element) via NymConnect

To download Element (chat client for Matrix) visit element.io. To connect to the Mixnet follow these steps:

  1. Start and connect NymConnect (or nym-socks5-client)
  2. Start element-desktop with --proxy-server argument:

Linux

element-desktop --proxy-server=socks5://127.0.0.1:1080

Mac

open -a Element --args --proxy-server=socks5://127.0.0.1:1080

To setup your own alias or key-binding see our Matrix NymConnect Integration guide.

Building Nym Platform

If you prefer to run to run nym-socks5-client the possibility is to download the pre-build binary or build the entire platform. To run ircd through the Mixnet nym-socks5-client and nym-network-requester are mandatory. Before you start with download and installation, make sure you are on the same machine from which you will connect to ircd.

We recommend to clone and build the entire platform instead of individual binaries as it offers an easier update and more options down the road, however it takes a basic command-line knowledge and more time. The Nym platform is written in Rust. For that to work we will need a few pre-requisities. If you prefer to download individual pre-build binaries, skip this part and go directly that chapter.

Prerequisites

  • Debian/Ubuntu: pkg-config, build-essential, libssl-dev, curl, jq, git
apt install pkg-config build-essential libssl-dev curl jq git
  • Arch/Manjaro: base-devel
pacman -S base-devel
  • Mac OS X: pkg-config , brew, openss1, protobuf, curl, git Running the following the script installs Homebrew and the above dependencies:
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
  • Rust & cargo >= 1.66

We recommend using the Rust shell script installer. Installing cargo from your package manager (e.g. apt) is not recommended as the packaged versions are usually too old.

If you really don’t want to use the shell script installer, the Rust installation docs contain instructions for many platforms.

Download and Compile Nym

The following commands will compile binaries into the nym/target/release directory:

rustup update
git clone https://github.com/nymtech/nym.git
cd nym
git checkout master # master branch has the latest release version: `develop` will most likely be incompatible with deployed public networks
cargo build --release # build your binaries with **mainnet** configuration

Quite a bit of stuff gets built. The key working parts for the workshop are:

Pre-built Binaries

The Github releases page has pre-built binaries which should work on Ubuntu 20.04 and other Debian-based systems, but at this stage cannot be guaranteed to work everywhere.

Download: Find the binary of your choice, right click on the binary, select Copy Link. This will save the binary <URL> to clipboard. Run the following commands on your machine:

wget <URL> # to download the binary

If the pre-built binaries don’t work or are unavailable for your system, you will need to build the platform yourself.

All Nym binaries must first be made executable.

To make a binary executable, open terminal in the same directory and run:

chmod +x ./<BINARY_NAME> 
# for example: chmod +x ./nym-network-requester

Initialize Socks5 Client and Network Requester

Whether you build the entire platform or downloaded binaries, nym-socks5-client and nym-network-requester need to be initialised with init before being run.

In your terminal navigate to the directory where you have your nym-socks5-client and nym-network-requester. In case you built the entire platform it’s in nym/target/release.

# change directory from nym repo
cd target/release

Network Requester

The init command is usually where you pass flags specifying configuration arguments such as the gateway you wish to communicate with, the ports you wish your binary to listen on, etc.

The init command will also create the necessary keypairs and configuration files at ~/.nym/<BINARY_TYPE>/<BINARY_ID>/ if these files do not already exist. It will NOT overwrite existing keypairs if they are present.

To run ircd through the Mixnet you need to run your own Network Requester and add known peer’s domains/addresses to ~/.nym/service-providers/network-requester/<NETWORK-REQUESTER-ID>/data/allowed.list. For all other applications nym-socks5-client (or NymCOnnect) is enough, no need to initialize and run nym-network-requester.

Here are the steps to initialize nym-network-requester:

# open the directory with your binaries
./nym-network-requester init --id <CHOOSE_ANY_NAME_AS_ID>

This will print you information about your client <ADDRESS>, it will look like:

The address of this client is: 8hUvtEyZK8umsdxxPS2BizQhEDmbNeXEPBZLgscE57Zh.5P2bWn6WybVL8QgoPEUHf6h2zXktmwrWaqaucEBZy7Vb@5vC8spDvw5VDQ8Zvd9fVvBhbUDv9jABR4cXzd4Kh5vz

Socks5 Client

If you run nym-socks5-client instead of NymConnect, you can choose your --provider here or leave that flag empty and your client will chose one randomly. To run ircd, you will need to connect it to your nym-network-requester by using your <ADDRESS> for your nym-socks5-client initialisation and add a flag --use-reply-surbs true. Run the command in the next terminal window:

# to connect to your nym-network-requester as a provider for ircd
./nym-socks5-client init --use-reply-surbs true --id <CHOSE_ANY_NAME_AS_ID> --provider <ADDRESS>

# simple socks5 client init (random provider) for other apps
./nym-socks5-client init --id <CHOSE_ANY_NAME_AS_ID>

Info

You can reconfigure your binaries at any time by editing the config file located at ~/.nym/service-providers/<BINARY_TYPE>/<BINARY_ID>/config/config.toml and restarting the binary process.

Run Clients

Once you have run init, you can start your binary with the run command, accompanied by the id of the binary that you specified.

This id is never transmitted over the network, and is used to select which local config and key files to use for startup.

# network requester
./nym-network-requester run --id <ID>

# socks5 client (in other terminal window)
./nym-socks5-client run --id <ID>

Troubleshooting

In case your nym-socks5-client has a problem to connect to your nym-network-requester try to setup a firewall by running these commands:

# check if you have ufw installed
ufw version

# if it is not installed, install with
sudo apt install ufw -y

# enable ufw
sudo ufw enable

# check the status of the firewall
sudo ufw status

# open firewall ports for network requester
sudo ufw allow 22,9000/tcp

# re-check the ufw status
sudo ufw status

Restart your network requester.

ircd

Dark.fi built a fully anonymous and p2p instance of IRC chat called ircd. The team is just finishing their new instance of the program darkirc which we hope to see in production soon.

Info

It is highly recomended to install dark.fi architecture prior to the workshop following the documentation so we have enough time for the network configuration.

Configuration

Make sure to have ircd installed on the same machine like your nym-socks5-client (nym-network-requester can run anywhere).

Currently nym-network-requester automatically connnects only to the whitelisted URLs. This will change soon into a more opened setup. This list can be changed by an operator running a node.

Edit allowed.list

  1. Open a text editor and add:
dasman.xyz
  1. Save it as allowed.list in ~/.nym/service-providers/network-requester/<NETWORK-REQUESTER-ID>/data/
  2. Restart your nym-network-requester
./nym-network-requester run --id <ID>
  1. Make sure both nym-socks5-client and nym-network-requester are running and connected

ircd setup

In case your ircd has problems to start or connect, run the following:

# cd to darkfi repo
git pull
git checkout c4b78ead5111b0423fca3bd53cb7185acd6f0faa

# compile ircd
make ircd

# in case of dependency error: "failed to load source for dependency `halo2_gadgets`"
rm Cargo.lock
make ircd

# remove the config file (rename it if you want to safe any values first)
rm ~/.config/darkfi/ircd_config.toml

# rerun ircd to generate new config file
./ircd

# add your custom values from the old config file
  1. Open ~/.config/darkfi/ircd_config.toml
  2. Coment the line with seeds
  3. Add line:
peers = ["nym://dasman.xyz:25552"]
  1. Change outbond_transports to:
outbond_transports = ["nym"]
  1. Make sure that
outbound_connections = 0
  1. Save and restart ircd

Observe the ircd deamon to see that the communication is running through the mixnet.

Bonus: Join hcpp23 channel

Now, when your Darkfi’s ircd runs through Nym Mixnet, you can join public and fully anonymous channel #hcpp23. To do so, follow one of the two possibilities:

  1. Run a command in your weechat:
/join #hcpp23
  1. Open ~/.config/darkfi/ircd_config.toml and add "#hcpp23" to the autojoin = [] brackets, save and restart ircd.
Last change: 2024-04-11, commit: f978552

HCPP23 - Building with Nym workshop

This is a reference page, to see the entire presentation join Max’s talk at HCPP 2023 on Satuday.

Mixnet architecture

Clients

SDKs

Rust examples

Typescript

Last change: 2024-04-11, commit: f978552

Nym General FAQ

If you have questions which are not answered below, please share them at our DevRel AMAs or seek support in Nym’s community

What is Nym?

Nym is a privacy platform that secures user data and protects against surveillance at the network level.

The platform does so by leveraging different technological components:

  • Nym Mixnet, a type of overlay network that makes both content and metadata of transactions private through mixing, network-level obfuscation and incentivisation (using Sphinx);
  • A blockchain called Nyx, our Cosmos SDK blockchain, to allow for us to use payment tokens in the form of NYM, as well as smart contracts, in order to create a robust, decentralized, and secure environment incentives for the Mixnet;
  • Coconut, a zero-knowledge signature scheme, that creates an application-level private access control layer to power Zk-Nyms;
  • A utility token NYM, to pay for usage, measure reputation and serve as rewards for the privacy infrastructure.

Simply put, the Nym network (“Nym”) is a decentralized and incentivized infrastructure to provision privacy to a broad range of message-based applications and services. Think of it as a “Layer 0” privacy infrastructure for the entire internet.

Related articles:

What’s the difference between Nym and VPNs?

Nym is not an onion routing system, it is not a decentralized VPN - it’s much more than that. Nym is a mixnet meant to stop precisely the traffic analysis attacks that Tor and dVPNs are vulnerable to.

It is an orthogonal design that maintains better privacy and can support anonymity, although usually with a cost in terms of latency. It basically is an infrastructure on which privacy preserving apps can be built, leveraging the Mixnet and Coconut credentials, amongst others. The Nym mixnet and VPNs differ because VPNs do not mix nor do they protect metadata from an adversary who may be able to watch the entire network.

Related articles:

What is Nym’s VPN?

Since Q2 2023 the Nym core team has been working on launching the first major consumer facing product that runs on top of the Nym mixnet: a high speed, trustless and decentralized VPN, paid for via the NYM token - facilitating anonymous payments if wished. The product positions itself as a full-network protection service available across all of a user’s devices, leveraging the Nym Mixnet and other primitives to offer split tunneling and traffic obfuscation techniques to protect against censorship.

Related articles:

Last change: 2024-04-11, commit: f978552

Integrations FAQ

On this page, you’ll find links and frequently asked questions on how to get started on integrating your project with Nym’s Mixnet and its blockchain, Nyx.

General Info

Codebase Info

Documentation Info

  • Documentation
  • Developer Portal - you are currently viewing the Developer Portal

Wallet Installation

The Nym wallet can be downloaded here.

You can find all the instructions related to setting up your wallet in the docs, as well as instructions on how to build the wallet if there is not a downloadable version built for your operating system.

What are the machine hardware requirements for Nym Wallet?

About 16GB of RAM is recommended for the wallet. However you can expect an average memory usage of ~100MB.

Interacting with the Nyx blockchain

Where can I find information on the blockchain, such as RPC endpoints?

You can find most information required for integration in the Cosmos Chain Registry and Keplr Chain Registry repositories.

How can I use JSON-RPC methods to interact with the Nyx blockchain?

There are multiple ways to use JSON-RPC methods to interact with the Nyx blockchain. Which method you use will depend on the type of application you are integrating Nyx interactions into.

  1. The standalone nyxd binary can be used for CLI wallets, interacting with smart contracts via the CLI, setting up RPC nodes, and even running validators. This is a version of the Cosmos Hub’s gaiad binary compiled with Nyx chain configuration, and is written in Go. Instructions on setting up the nyxd binary can be found here. This is recommended for more complex commands. For full documentation check the gaiad documentation.

  2. CosmJS is a Typescript library allowing for developers to interact with CosmosSDK blockchains from a Javascript or Typescript project. You can find it on Github here and an explainer of its functionality in the Cosmos Developer Portal. You can find a list of example apps which use CosmJS here.

  3. The Nym-CLI tool, a standalone rust binary which can be built and used according to the docs can be used in much the same way as nyxd. It is a bit simpler to use than the nyxd binary, but is not recommended for complex queries, and not all commands are currently implemented. A list of Nym CLI commands and example usage can be found here

How do I generate an address/mnemonic for users to interact with?

Nyxd

Use the following command, replacing your_id with the ID you want to use for your keypair:

./nyxd keys add your_id --chain-id=nyx --gas=auto --gas-adjustment=1.4 --fees=7000unym

Nym-CLI

./nym-cli account create

Both methods will generate a keypair and log the mnemonic in the console.

CosmJS

You can find example code for keypair generation here.

How to get block information like block height, block hash, block time as so on?

Nyxd

You would use one of the subcommands returned by this command:

./nyxd query tx --chain-id=nyx --gas=auto --gas-adjustment=1.4 --fees=7000unym

Nym-CLI

./nym-cli block current-height

CosmJS

CosmJS documentation can be found here. We will be working on example code blocks soon.

How to get account/address balance to check there is enough coins to withdraw?

Nyxd

./nyxd query bank balances <address> --chain-id=nyx --gas=auto --gas-adjustment=1.4 --fees=7000unym

Nym-CLI

./nym-cli account balance

CosmJS

CosmJS documentation can be found here. We will be working on example code blocks soon.

How do I transfer tokens to another address?

Nyxd

./nyxd tx bank send [from_key_or_address] [to_address] [amount] --chain-id=nyx --gas=auto --gas-adjustment=1.4 --fees=7000unym

Nym-CLI

./nym-cli account send TARGET_ADDRESS AMOUNT

CosmJS

CosmJS documentation can be found here. We will be working on example code blocks soon.

Does the address support the inclusion of a memo or destinationTag when doing the transfer?

Yes, it is supported.

Can I use my Ledger hardware wallet to interact with the Nyx blockchain?

Yes. Follow the instructions in the Ledger support for Nyx documentation.

Where can I find network details such as deployed smart contract addresses?

In the network defaults file.

NYM Token

The token used to reward mixnet infrastructure operators - NYM - is one of the native tokens of the Nyx blockchain. The other token is NYX.

NYM is used to incentivise the mixnet, whereas NYX is used to secure the Nyx blockchain via Validator staking.

Integration with Nym’s technology stack will most likely involve using NYM if you do need to interact with the Nyx blockchain and transfer tokens.

I’ve seen an ERC20 representation of NYM on Ethereum - what’s this and how do I use it?

We use the Gravity Bridge blockchain to bridge an ERC20 representation of NYM between the Cosmos ecosystem of IBC-enabled chains and Ethereum mainnet. Gravity Bridge is its own IBC-enabled CosmosSDK chain, which interacts with a smart contract deployed on Ethereum mainnet.

The ERC20 representation of NYM cannot be used with the mixnet; only the native Cosmos representation is usable for staking or bonding nodes.

If you need to transfer tokens across the bridge, we recommend users use Cosmostation’s spacestation.zone dApp with Metamask and Keplr.

What is Circulating Supply and how to find out the distribution amount?

Circulating supply is the total number of available NYM. NYM is currently present on the IBC-enabled Nyx blockchain, as well as in ERC20 form on Ethereum Mainnet.

The Validator API endpoints can be found via the Swagger Documentation. The following endpoints can be called to retrieve the correct distribution amount and circulating supply within Nym.

Using this API endpoint returns information about the circulating supply of Nym tokens:

/circulating-supply

Query Response:

{
    "total_supply": {
        "denom": "unym",
        "amount": "1000000000000000"
    },
    "mixmining_reserve": {
        "denom": "unym",
        "amount": "241105338883248"
    },
    "vesting_tokens": {
        "denom": "unym",
        "amount": "390255200928865"
    },
    "circulating_supply": {
        "denom": "unym",
        "amount": "368639460187887"
    }
}
  • total_supply- The total number of NYM tokens that have been created and can exist, including those that are currently in circulation and those that are reserved for various purposes.

  • mixmining_reserved- The number of NYM tokens that are reserved for the mixnet miners who help to power the Nym network.

  • vesting_tokens- The number of NYM tokens that are subject to vesting, meaning they are gradually released over time to certain stakeholders such as the team, advisors, and early investors.

  • circulating_supply- The number of NYM tokens that are currently in circulation and available to be traded on the open market, which is calculated by subtracting the mixmining_reserved and vesting_tokens from the total_supply.

Using this API endpoint returns the current value of the total supply of NYM tokens:

/circulating-supply/total-supply-value

Query Response:

1000000000.0 

The maximum number of NYM tokens that can ever be created is 1 billion.

Using this API endpoint returns the current value of the circulating supply of NYM tokens:

/circulating-supply/circulating-supply-value

Query Response:

368639460.187887

This refers to the present quantity of NYM tokens that are actively in circulation.

Sending traffic through the Nym mixnet

Is the mixnet free to use?

For the moment then yes, the mixnet is free to use. There are no limits on the amount of traffic that an app can send through the mixnet.

Do I need to run my own gateway to send application traffic through the mixnet?

No, although we do recommend that apps that wish to integrate look into running some of their own infrastructure such as gateways in order to assure uptime.

How can I find out if an application is already supported by network requester services?

You can check the default allowed list file to see which application traffic is whitelisted by default. If the domain is present on that list, it means that existing network requesters can be used to privacy-protect your application traffic. Simply use NymConnect to connect to this service through the mixnet.

Currently we are undergoing changes on this policy under the name Project Smoosh where a new type of node Exit Gateway will allow users to connect to much wider range of domains, restricted by our new exit policy. Follow the changes here.

Last change: 2024-04-11, commit: f978552

Rewards FAQ

On this page you will find important information about participation in community activities which involve NYM token rewards, such as contests, giveaways, and promotions. Before participating in any such activity, make sure to read this page carefully.

Am I eligible to participate? What are the conditions?

Participation in any program or community activity involving NYM token rewards is only available to individuals who do not reside in locations that makes them ineligible to participate and/or receive prizes, including:

The USA, Central African Republic, Cuba, Iran, Iraq, Lebanon, Libya, North Korea, Somalia, South Sudan, Sudan, Syria, Venezuela, Yemen, and Russian occupied regions of Ukraine (including Crimea, and parts of Donetsk and Luhansk).

Be nice and play fair! Nym reserves the right to determine the final outcome of its programs and community activities and disqualify any participants without prior notice or recourse for any reason, including fraudulent behavior and failure to adhere to the Nym Code of Conduct.

I won NYM rewards. How can I claim them?

First things first: congratulations! We hope you had some fun in the process. A Nym Community Manger will tag you on Telegram or Discord - send them a private message to start the claim process. You will receive your unique reward ID and detailed instructions on how to use it to claim your rewards. Remember: we never DM you first!

Note: you have 2 weeks to claim your rewards! If we don’t hear from you, your reward ID will expire.

Do I need to pass KYC?

Before receiving NYM token rewards, you are required to successfully complete KYC verification with Synaps, our KYC provider. You only need to do this once!

This is my first time - How do I pass KYC?

To claim your rewards, you will be asked to provide your email address. If you haven’t passed KYC yet, your email address will be added to our KYC whitelist and you will receive a welcome email from Synaps with instructions on how to start the KYC process. Once you complete KYC and provide a valid Nym wallet address, your rewards will be transferred to your wallet automatically.

Note: it may take up to 2 weeks for your email address to get whitelisted. Be patient and keep an eye on your inbox!

To receive your tokens, you will need a Nym wallet address. If you don’t already have one, download the Nym wallet and create an account. You can copy your wallet address from the “receive” tab of the wallet. Make sure to keep your mnemonic safe, as losing that means losing your tokens.

Tip: If you are not sure you have completed Nym KYC before, visit our KYC portal on Synaps and try to log in with your email.

I have already passed KYC on Synaps. What do I need to do next?

If you have successfully completed KYC on Synaps earlier and provided your Nym wallet address, you are all set - we will send you a link so you can claim your rewards.

Note: after claiming your NYM rewards, it may take up to 3 weeks for the tokens to be transferred to your wallet. Be patient and keep an eye on your wallet!

I received my NYM tokens. What can I do with them?

We’re glad you asked! The Nym network is the most robust privacy infrastructure the world has ever seen, and the NYM token is how you can access its utility:

  • As a user, unparalleled privacy for your communications
  • As a mix node operator, rewards for your crucial role in operating our decentralized privacy infrastructure
  • As a delegator, rewards for securing the Nym network and ensuring outstanding quality of service

Using the Nym network is free for now, but user fees will be introduced in the future and those will be paid in NYM tokens, so set them aside! And until then, you can contribute to running our decentralized infrastructure and earn mix mining rewards by setting up Nym mix nodes and bonding your tokens to them. You don’t need to run nodes to contribute to the security and performance of the Nym network though. You can pledge your trust in someone else’s node by delegating your NYM tokens to it, and receive a share of their mix mining rewards.

You can find out more about how staking works in this video from our Chief Scientist Claudia Diaz and if you need help setting up your mix node, choosing one to delegate your tokens to, or anything else, our community is there to help on Discord and Telegram.

Last change: 2024-04-11, commit: f978552

DevRel AMAs

The Nym Technology Developer Relations AMA (Ask Me Anything) is an event organised by the Nym team to engage and connect with the developer community as well as answer any questions that they may have.

⚠️ Hosted every fortnight on Wednesday @ 4pm UTC

Archives of these calls can be found here.

Last change: 2024-04-11, commit: f978552

Community Applications

If you would like to share your application here, please submit a pull request to the main branch of the nymtech/dev-portal repository.

Pastenym

A pastebin inspired project, offer a solution for sharing text with Nym products to offer full anonymity, even on metadata level.

Nostr-Nym

Nostr-nym offer a solution to use Nostr protocol by giving the possibility to run a relay on mixnet. By using a nostr client compatible with the mixnet, users can protect their privacy to be able to use Nostr has the want, without being observed.

Spook

Ethereum RPC request mixer uses the Nym network mixing service to anonymize RPC requests to the Ethereum network without revealing sensitive data and metadata.

Ethereum Transaction Broadcaster

Ethereum Transaction Broadcaster that uses the Nym Mixnet to provide privacy and anonymity for transactions on the Ethereum network command-line interface.

NymDrive

An open-source, decentralized, E2E encrypted, privacy friendly alternative to Google Drive/Dropbox, allowing for file encryption and decryption using the Nym Mixnet.

Nym Dashboard

Developed by No Trust Verify, this dashboard is a great tool to get information about the mixnet, gateways and mixnodes.

Is Nym Up

Explore whether we’re up through IsNymUp, a tool that helps check the heath of the Nym network as well as some mixnet related statistics!

DarkFi over Nym

DarkFi leverages Nym’s mixnet as a pluggable transport for IRCD, their p2p IRC variant. Users can anonymously connect to peers over the network, ensuring secure and private communication within the DarkFi ecosystem.

Nymstr email

Experience secure and private email communication with ease using Nymstr email, which enables seamless transmission of emails over a SOCKS5 proxy and our NYM mixnet!

Minibolt

Proxies the clearnet connections of a Bitcoin node and its associated tools using the NYM mixnet.

NymGraph

NymGraph is a graphical chat client for Nym running on Ubuntu and Debian. Test it to chat over the Nym network!



Community Guides

We aren’t the only ones writing documentation: the Nym developer community is also a great source of guides and resources, some of which we’ve included here.

No Trust Verify

No Trust Verify is a project that aims to build open-source, privacy-enhancing technologies that make it easier to use the Internet securely and anonymously. Their focus is on providing tools and services that make it simple for developers to create decentralized applications (dApps) that respect users’ privacy.

The Way of the NYMJA

by Pineapple Proxy🍍

Born out of a study group from Nym’s Shipyard Academy, Pineapple Proxy has emerged as a cluster of motivated and skilled individuals who see the new internet taking shape. With vibecare at the heart of their approach, this zesty collective is on a mission to make privacy convenient for everyone via content, new tools, events, and novel experiences. They believe in collective intelligence, empathy, and collaboration as the means by which privacy will become a meaningful reality.

Last change: 2024-04-11, commit: f978552

Change Service Grantee Information

If you wish to update any of the following information:

  • Email Address
  • NYM address
  • Network Requester
  • Gateway ID Key
  • Gateway Address
  • Service
  • Payment Address

Please reach out either in the #service-grantees channel on Discord or on Matrix.

Last change: 2024-04-11, commit: f978552

Code of Conduct

We are committed to providing a friendly, safe and welcoming environment for all, regardless of level of experience, gender identity and expression, sexual orientation, disability, personal appearance, body size, race, ethnicity, age, religion, nationality, or other similar characteristic.

Please avoid using overtly sexual aliases or other nicknames that might detract from a friendly, safe and welcoming environment for all.

Please be kind and courteous. There’s no need to be mean or rude.

Respect that people have differences of opinion and that every design or implementation choice carries a trade-off and numerous costs. There is seldom a right answer.

Please keep unstructured critique to a minimum. If you have solid ideas you want to experiment with, make a fork and see how it works.

We will exclude you from interaction if you insult, demean or harass anyone. That is not welcome behaviour. We interpret the term “harassment” as including the definition in the Citizen Code of Conduct; if you have any lack of clarity about what might be included in that concept, please read their definition. In particular, we don’t tolerate behaviour that excludes people in socially marginalized groups.

Private harassment is also unacceptable. No matter who you are, if you feel you have been or are being harassed or made uncomfortable by a community member, please contact one of the channel ops or any of the Rust moderation team immediately. Whether you’re a regular contributor or a newcomer, we care about making this community a safe place for you and we’ve got your back.

Likewise any spamming, trolling, flaming, baiting or other attention-stealing behaviour is not welcome.

Last change: 2024-04-11, commit: f978552

Licensing

As a general approach, licensing is as follows this pattern:

For accurate information, please check individual files.

Last change: 2024-04-11, commit: f978552