Skip to content

Citadel SDK

Moat (a.k.a. the Citadel SDK) is a Software Development Kit allowing developers to implement SSI solutions using Citadel and the Dusk Blockchain. In the next subsections we explain how to use it.

You can find the complete API here, and a complete example using such API here.


Moat requires a reachable Rusk node installed and running, or selecting a trusted one. You can set up a node as explained here. It also requires an installed wallet connected to the given Rusk node, as explained here.

Using the CLI

To use the CLI, you first need to clone the following repository:

Terminal window
git clone
cd moat

Now, specify the Rusk node address in moat-cli/config.toml. Then, you can execute the CLI for any of the involved parties, as follows.


Terminal window
cargo r --release --bin moat-cli-user -- --wallet-pass <PASSWORD>

License Provider

Terminal window
cargo r --release --bin moat-cli-lp -- --wallet-pass <PASSWORD>

Service Provider

Terminal window
cargo r --release --bin moat-cli-sp -- --wallet-pass <PASSWORD>

Import the Required Modules

To use Moat, you need the zk-citadel-moat Rust crate, available here. In order to use it, you are required to add it as a dependency in your Cargo.toml and to use the following modules in your code.

use dusk_jubjub::JubJubScalar;
use rand::rngs::OsRng;
use zk_citadel_moat::api::{Error, MoatContext, MoatCore};

Create a Moat Context

The first thing to do to use the different options given by Moat, is to specify some settings by means of a Moat Context, as follows.

// Specify a configuration file path to connect to the Blockchain
let config_path = "./config.toml";
// Specify a wallet file path and its encryption password
let wallet_path = concat!(env!("HOME"), "/.dusk/rusk-wallet/wallet.dat");
let wallet_password = "password";
// Specify the gas configuration for the transactions
let gas_limit = 500000000;
let gas_price = 1;
// Build a configuration object with the previously set information
let moat_context = MoatContext::create(

Retrieve Credentials from the Installed Wallet

You can choose to use the same credentials used by the wallet in your Citadel application as well. To get them, you as do as follows.

// Retrieve the keypair from the installed wallet
let (psk, ssk) = MoatCore::get_wallet_keypair(&moat_context)?;

Request a License

The user can request a license on-chain. In order to create a transaction including that request, it will be necessary to provide the public key psk_lp of the LP, doing as follows.

// Submit a request to the Blockchain
let request_hash = MoatCore::request_license(
&mut OsRng,

Get Owned Requests

The LP can retrieve all the requests belonging to them (using their secret key ssk_lp) from the Blockchain, as follows.

// Get owned requests
let requests = MoatCore::get_owned_requests(&ssk_lp, &moat_context).await?;

Issuing a License

After receiving a request, the LP can issue a license for that given request. First, it is required to set the attribute data as follows.

// Set attribute data to, for instance, 1234
let attr_data = JubJubScalar::from(1234u64);

The LP can now create a transaction which will issue a license, as follows.

// Issue a license
let rng = &mut OsRng;
let license_hash = MoatCore::issue_license(
requests.get(0).expect("A request was owned."),

Get Owned Licenses

The user can use their secret key to list the owned licenses, as follows.

let licenses =
MoatCore::get_owned_licenses(&ssk_user, &moat_context).await?;

Use a License

To use a license, the user first needs to set the challenge value c, which allows to use the license under certain conditions specified by the SP. It can be done as follows.

// Set challenge to, for instance, 1234
let challenge = JubJubScalar::from(1234u64);

The user can now create a transaction using a given license, providing the public key psk_sp of the SP. In this step, a session will be created in the contract’s state, and a session cookie will be provided in the process.

let session_cookie = MoatCore::use_license(
licenses.get(0).expect("A license was owned."),
.expect("session cookie has been obtained");

The SP can verify if a given session cookie is correct. Upon success, it will mean that the requested service in such process shall be granted. It can be done as follows.

if MoatCore::verify_requested_service(
println!("Session Cookie was correct, service should be granted.");
} else {
println!("Session Cookie was not correct, service must be denied.");

Additionally, the SP should verify the challenge used by the user, as follows.

if session_cookie.c == challenge {
// grant service