# Niftyzk tutorial 4 - Ceremony

By [strawberry](https://paragraph.com/@strawberry-52) · 2025-01-11

---

In this tutorial, we will create a circuit, compile it and then deploy our ceremony server on a VPS to accept anonymous contributions. After this we will finalize the circuit and export the final Verification key

Let’s run `niftyzk init projectname` to create a new project

    Creating a new directory with name projectname
    ? What project do you want to scaffold? Commit-Reveal Scheme
    ? Choose the hashing algorithm to use:  poseidon
    ? Do you wish to add tamperproof public inputs? (E.g: walletaddress):  no
    Generating circuits
    Generating javascript
    Done
    Run npm install in your project folder
    

So run `npm install` and let’s download the ptau files

`niftyzk ptaufiles` , we are going to grab a smaller file for our commit-reveal scheme

    ? Select a ptau file to download powersOfTau28_hez_final_14.ptau
    Connecting to download powersOfTau28_hez_final_14.ptau
    Starting to download 18.08 MiB
    downloading [====================] 100% 0.0s
    

Now just run `niftyzk compile` and select the ptau file, so far so good.

Now run `git init` and do a `git add .`

If you check `git status` You should see;

    $ git status
    On branch master
    
    No commits yet
    
    Changes to be committed:
      (use "git rm --cached <file>..." to unstage)
        new file:   .gitignore
        new file:   circuits/circuit.circom
        new file:   circuits/commitment_hasher.circom
        new file:   circuits/compiled/circuit.r1cs
        new file:   circuits/compiled/circuit.sym
        new file:   circuits/compiled/circuit_js/circuit.wasm
        new file:   circuits/compiled/circuit_js/generate_witness.js
        new file:   circuits/compiled/circuit_js/witness_calculator.js
        new file:   circuits/compiled/zkeys/circuit_0000.zkey
        new file:   lib/index.js
        new file:   package-lock.json
        new file:   package.json
        new file:   readme.md
        new file:   test/index.test.js
        new file:   test/input.js
    

These are the files that were created during the scaffold and compilation. You can see the `circuits/compiled` directory contains all the artifacts outputted by the compiler and there is the zkey which will be used for contributions during the ceremony. The ptau files are not commited due to their size but you can always just download them again.

Let’s commit the files

    
    $ git commit -m "initial commit"
    [master (root-commit) 946c8e7] initial commit
     15 files changed, 7212 insertions(+)
     create mode 100644 .gitignore
     create mode 100644 circuits/circuit.circom
     create mode 100644 circuits/commitment_hasher.circom
     create mode 100644 circuits/compiled/circuit.r1cs
     create mode 100644 circuits/compiled/circuit.sym
     create mode 100644 circuits/compiled/circuit_js/circuit.wasm
     create mode 100644 circuits/compiled/circuit_js/generate_witness.js
     create mode 100644 circuits/compiled/circuit_js/witness_calculator.js
     create mode 100644 circuits/compiled/zkeys/circuit_0000.zkey
     create mode 100644 lib/index.js
     create mode 100644 package-lock.json
     create mode 100644 package.json
     create mode 100644 readme.md
     create mode 100644 test/index.test.js
     create mode 100644 test/input.js
    

Go over to your favorite git hosting solution, I’m using github but you can use whatever you want and push the repository. We will clone it to a VPS later, but you can also copy the whole directory there manually, that’s up to you.

The repository is here for reference:

[https://github.com/NiftyZk/projectname](https://github.com/NiftyZk/projectname)

**Manual Deployment**

For the VPS, I’m creating a Hetzner server. You can use any hosting solution, or even self-host on a raspberry pi. You will need SSH to log in. We will configure Nginx and even configure a domain using namecheap.

On console.hetzner.cloud I created a 2VCPU, 4 GB Ram X86 VPS for €4.11/month running Ubuntu, and configured it with my SSH keys. If you are new to SSH you should invest some time to learn about it.

`ssh root@serverip`

So I’m connecting to the remote VPS I created with the SSH client, I’m connecting as root as there are no other users configured. You can configure that for yourself, it’s out of scope for now for showcasing the ceremony.

`sudo apt update`

`sudo apt upgrade`

`sudo apt install nginx`We install snap for certbot

`sudo apt install snapd`

`sudo snap install --classic certbot`

`sudo ln -s /snap/bin/certbot /usr/bin/certbot`

`sudo certbot --nginx`

You should configure your domain to have an A record with host `@` pointing to the IP of your VPS for certbot to issue the certificate. Your DNS changes will take time to propagate but if you did everything well, the IP address should already show NGINX is running.

Next we are going to install nodejs using the official docs

[https://nodejs.org/en/download](https://nodejs.org/en/download)

`curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.1/install.sh | bash`

This installs nvm and you might need to restart the ssh session after installation. Install a new node version using nvm

`nvm install 22`

We are going to install pm2, this will help keep the ceremony server open when the ssh session is closed.

`npm install -g pm2`

`pm2 startup systemd`

Clone the repository we created earlier using Git to your home directory and don’t forget to install niftyzk

`npm install -g git+https://github.com/NiftyZk/niftyzk.git`

Next step is to configure nginx to proxy the port 3000 to 443 SSL and upgrade all non-SSL connections to use it.You need to copy this file to `/etc/nginx/sites-available/default` and make sure to **edit YOURDOMAIN parts to use your configured domain name**!

    server {
            #SSL only
            listen 443 ssl default_server;
            listen [::]:443 ssl default_server;
            client_max_body_size 200M;
    
            ssl_certificate /etc/letsencrypt/live/YOURDOMAIN/fullchain.pem; # managed by Certbot
            ssl_certificate_key /etc/letsencrypt/live/YOURDOMAIN/privkey.pem; # managed by Certbot
            include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot
            ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot
    
    
            server_name YOURDOMAIN;
    
            location / {
                    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
                    proxy_set_header X-NginX-Proxy true;
                    proxy_set_header Host $host;
                    proxy_set_header Upgrade $http_upgrade;
                    proxy_set_header X-Real-IP $remote_addr;
                    proxy_set_header Connection ‘upgrade’;
                    proxy_pass http://127.0.0.1:3000; #port where you are serving your express app.
                    proxy_http_version 1.1;
                    proxy_cache_bypass $http_upgrade;
                    proxy_ssl_server_name on;
                    proxy_pass_header Server;
                    proxy_cache_bypass $http_upgrade;
                    proxy_redirect off;
            }
    }
                                                            
    server {
            listen 80;
            listen [::]:80;
            server_name _;
    
            return 301 https://$host$request_uri;
    
    }
    

Then after editing the file, reload nginx

`sudo systemctl reload nginx`

Now, we are going to create a shell script to execute niftyzk ceremony, that can be ran by pm2

`cd` into your cloned project’s directory and `npm install` then `touch run.sh` and open it with an editor.

    #!/usr/bin/bash
    niftyzk ceremony
    

Download the used ptau file with `niftyzk ptaufiles` , we used the 14th for compiling, you must select the same.To finally run the ceremony, `pm2 start run.sh`

Congrats, you got the ceremony server running on your domain.When you visit it you should see this:

![](https://storage.googleapis.com/papyrus_images/6baabad8a2eb4cfdbd1450613687153368353fe2c02a09921b21137f7e2a9835.png)

**How does it work?**

Anyone can visit your ceremony, the participation is public. They enter a name and then they are placed in a queue. When it’s their turn to contribute, they will be prompted to enter some entropy and on the client side they run SnarkJS to make a contribution to the last zkey.

The participation in the ceremony can be verified by downloading the log file and comparing the entries in the log file with the sha256 hash of your name.

A directory have been added to your repository called contributions, that contains the log.csv file.

So let’s enter the name: `helloworld` and add some random entropy.What happened? A contribution was added to the `/circuits/compiled/zkeys/` directory called `circuit_0001.zkey` and the log file has a csv entry added

    Contribution,936a185caaa266bb9cbe981e9e05cb78cd732b0b3280eb944412bb6f8f8f07af,087ec9f31cc05fa8db3c46ed360a5294fd6c99aaa97e244044ca936c3e302e35cd34080e86eaa4a67d1e2c717d25b90759f46cb4af692ac5b3e2d17f04bacbfa,circuit_0001.zkey
    

The first hash is a sha256 hash of the name entered, the second is the blake2b hash of the circuit which will be later logged on circuit finalization.

     echo -n helloworld | sha256sum 
    936a185caaa266bb9cbe981e9e05cb78cd732b0b3280eb944412bb6f8f8f07af  -
    

The ceremony can be online indefinitely and as long as one of the contributors don’t cheat, it’s secure. The largest PTAU file the ceremony server supports can be logged with `niftyzk ptaufiles`

    powersOfTau28_hez_final_15.ptau blake2b hash: 982372c867d229c236091f767e703253249a9b432c1710b4f326306bfa2428a17b06240359606cfe4d580b10a5a1f63fbed499527069c18ae17060472969ae6e Power: 15, Max Constraints: 32K Size: 36.08 MiB Supports built in ceremony server: YES
    

The reason for this is the networking bottleneck. **Any circuits that require more than max 32k constraints will need to do a ceremony manually using snarkjs.**

So after a few contributions, you can take down the server. For testing now we can add contributions manually.

Then do a `git add .`

    root@niftyzk-ceremony:/home/nifty/projectname# git status
    On branch master
    Your branch is up to date with 'origin/master'.
    
    Changes to be committed:
      (use "git restore --staged <file>..." to unstage)
        new file:   circuits/compiled/contributions/log.csv
        new file:   circuits/compiled/zkeys/circuit_0001.zkey
        new file:   circuits/compiled/zkeys/circuit_0002.zkey
        new file:   circuits/compiled/zkeys/circuit_0003.zkey
        new file:   run.sh
    

And commit these zkeys and push to your repository.You can turn off your webserver now.

**Finalize the circuit**

You can finalize the ceremony locally, just pull the changes and select a random beacon to use.

`niftyzk finalize --beacon 0000000000000000000102b8a74a6e9b9344f0abb3ba25dea7f847c7296fb21d`

Niftyzk finalize will complete the ceremony, I used a bitcoin block hash for a beacon. It should be a verifiable hexadecimal number.

When the finalization finished, you should see the contributions are logged.It will be always verifiable that your contribution is in the final zkey as long as you know the name you entered.

    [INFO]  niftyzk: contribution #1 936a185caaa266bb9cbe981e9e05cb78cd732b0b3280eb944412bb6f8f8f07af:
                    087ec9f3 1cc05fa8 db3c46ed 360a5294
                    fd6c99aa a97e2440 44ca936c 3e302e35
                    cd34080e 86eaa4a6 7d1e2c71 7d25b907
                    59f46cb4 af692ac5 b3e2d17f 04bacbfa
    [INFO]  niftyzk: ZKey Ok!
    

This creates the `circuit.final.zkey`

Now you can run `niftyzk vkey --final` and create the final `verification_key.json`now your circuit is secure and ready for production.

---

*Originally published on [strawberry](https://paragraph.com/@strawberry-52/niftyzk-tutorial-4-ceremony)*
