Skip to main content

Getting started with ICICLE

This guide is oriented towards developers who want to start writing code with the ICICLE libraries. If you just want to run your existing ZK circuits on GPU refer to this guide please.

ICICLE repository overview

ICICLE API overview

The diagram above displays the general architecture of ICICLE and the API layers that exist. The CUDA API, which we also call ICICLE Core, is the lowest level and is comprised of CUDA kernels which implement all primitives such as MSM as well as C++ wrappers which expose these methods for different curves.

ICICLE Core compiles into a static library. This library can be used with our official Golang and Rust wrappers or linked with your C++ project. You can also implement a wrapper for it in any other language.

Based on this dependency architecture, the ICICLE repository has three main sections:

ICICLE Core

ICICLE Core is a library that directly works with GPU by defining CUDA kernels and algorithms that invoke them. It contains code for fast field arithmetic, cryptographic primitives used in ZK such as NTT, MSM, Poseidon Hash, Polynomials and others.

ICICLE Core would typically be compiled into a static library and either used in a third party language such as Rust or Golang, or linked with your own C++ project.

ICICLE Rust and Golang bindings

These bindings allow you to easily use ICICLE in a Rust or Golang project. Setting up Golang bindings requires a bit of extra steps compared to the Rust bindings which utilize the cargo build tool.

Running ICICLE

This guide assumes that you have a Linux or Windows machine with an Nvidia GPU installed. If you don't have access to an Nvidia GPU you can access one for free on Google Colab.

note

ICICLE can only run on Linux or Windows. MacOS is not supported.

Prerequisites

  • NVCC (version 12.0 or newer)
  • cmake 3.18 and above
  • GCC - version 9 or newer is recommended.
  • Any Nvidia GPU
  • Linux or Windows operating system.

Optional Prerequisites

If you don't wish to install these prerequisites you can follow this tutorial using a ZK-Container (docker container). To learn more about using ZK-Containers read this.

Setting up ICICLE and running tests

The objective of this guide is to make sure you can run the ICICLE Core, Rust and Golang tests. Achieving this will ensure you know how to setup ICICLE and run an ICICLE program. For simplicity, we will be using the ICICLE docker container as our environment, however, you may install the prerequisites on your machine and skip the docker section.

Setting up environment with Docker

Lets begin by cloning the ICICLE repository:

git clone https://github.com/ingonyama-zk/icicle

We will proceed to build the docker image found here:

docker build -t icicle-demo .
docker run -it --runtime=nvidia --gpus all --name icicle_container icicle-demo
  • -it runs the container in interactive mode with a terminal.
  • --gpus all Allocate all available GPUs to the container. You can also specify which GPUs to use if you don't want to allocate all.
  • --runtime=nvidia Use the NVIDIA runtime, necessary for GPU support.

To read more about these settings reference this article.

If you accidentally close your terminal and want to reconnect just call:

docker exec -it icicle_container bash

Lets make sure that we have the correct CUDA version before proceeding

nvcc --version

You should see something like this

nvcc: NVIDIA (R) Cuda compiler driver
Copyright (c) 2005-2023 NVIDIA Corporation
Built on Tue_Aug_15_22:02:13_PDT_2023
Cuda compilation tools, release 12.2, V12.2.140
Build cuda_12.2.r12.2/compiler.33191640_0

Make sure the release version is at least 12.0.

ICICLE Core

ICICLE Core is found under <project_root>/icicle. To build and run the tests first:

cd icicle

For this example, we are going to compile ICICLE for a bn254 curve. However other compilation strategies are supported.

mkdir -p build
cmake -S . -B build -DCURVE=bn254 -DBUILD_TESTS=ON
cmake --build build -j

-DBUILD_TESTS option compiles the tests, without this flag ctest won't work. -DCURVE option tells the compiler which curve to build. You can find a list of supported curves here.

The output in build folder should include the static libraries for the compiled curve.

To run the test

cd build/tests
ctest

ICICLE Rust

The rust bindings work by first compiling the CUDA static libraries as seen here. The compilation of CUDA and the Rust library is all handled by the rust build toolchain.

Similar to ICICLE Core here we also have to compile per curve.

Lets compile curve bn254

cd wrappers/rust/icicle-curves/icicle-bn254

Now lets build our library

cargo build --release

This may take a couple of minutes since we are compiling both the CUDA and Rust code.

To run the tests

cargo test

We also include some benchmarks

cargo bench

ICICLE Golang

The Golang bindings require compiling ICICLE Core first. We supply a build script to help build what you need.

Script usage:

./build.sh [-curve=<curve>] [-field=<field>] [-hash=<hash>] [-cuda_version=<version>] [-g2] [-ecntt] [-devmode]

curve - The name of the curve to build or "all" to build all supported curves
field - The name of the field to build or "all" to build all supported fields
hash - The name of the hash to build or "all" to build all supported hashes
-g2 - Optional - build with G2 enabled
-ecntt - Optional - build with ECNTT enabled
-devmode - Optional - build in devmode
note

If more than one curve or more than one field or more than one hash is supplied, the last one supplied will be built

Once the library has been built, you can use and test the Golang bindings.

To test a specific curve, field or hash, change to it's directory and then run:

go test ./tests -count=1 -failfast -timeout 60m -p 2 -v

You will be able to see each test that runs, how long it takes and whether it passed or failed

Running ICICLE examples

ICICLE examples can be found here these examples cover some simple use cases using C++, rust and golang.

Lets run one of our C++ examples, in this case the MSM example.

cd examples/c++/msm
./compile.sh
./run.sh
tip

Read through the compile.sh and CMakeLists.txt to understand how to link your own C++ project with ICICLE

Running with Docker

In each example directory, ZK-container files are located in a subdirectory .devcontainer.

msm/
├── .devcontainer
├── devcontainer.json
└── Dockerfile

Now lets build our docker file and run the test inside it. Make sure you have installed the optional prerequisites.

docker build -t icicle-example-msm -f .devcontainer/Dockerfile .

Lets start and enter the container

docker run -it --rm --gpus all -v .:/icicle-example icicle-example-msm

Inside the container you can run the same commands:

./compile.sh
./run.sh

You can now experiment with our other examples, perhaps try to run a rust or golang example next.