Get started
Quickstart
You'll build a small Rust program whose core refuses to run without a Sigil license. Then you'll issue a license in the portal, activate it, and watch the install appear. The steps are the same ones you'll use on your real codebase.
rustup update), and curl and tar. This quickstart builds a native program. Protecting a .wasm works the same way, and Protect a WASM module covers the differences.Sign in to the portal
Open sigil.enigmahq.sh/portal and choose Sign in with conFIEL Auth. On your first sign-in Sigil creates your account, named after your organisation, with the seat pool your conFIEL entitlement includes. Every license you issue draws machines from that pool.
Register your application
Go to Applications → Register an application and give it a name, for example conFIEL Engine. Sigil generates an Ed25519 signing key for it. Copy the application id (app_…) from the application's page.
Create a policy
A policy is a tier: what a license unlocks, where it may run, and how long it works offline. On the application's page, under New policy:
| Field | Value | Why |
|---|---|---|
| Name | Engine | Shown when you issue licenses. |
| Entitlements | cosign | The feature name your code will require. |
| Platforms | Server | Native programs activate as server. |
| Machines per license | 1 | Seats each license takes from your pool. |
| Lease / grace | 14 / 7 days | How long an install keeps working offline. |
Download the SDK
The Rust SDK is a tarball for now; it will move to GitHub releases. Check it against the published SHA-256 and unpack it next to where your project will live:
$ curl -fLO https://sigil.enigmahq.sh/downloads/sigil-sdk-rust-0.2.0.tar.gz
$ echo "01d38edffdcfe0138b50fe8d66d243b6704164d2910938f1cb12a0a19dbc24a8 sigil-sdk-rust-0.2.0.tar.gz" | shasum -a 256 -c
sigil-sdk-rust-0.2.0.tar.gz: OK
$ tar xzf sigil-sdk-rust-0.2.0.tar.gzThis gives you sigil-sdk-rust-0.2.0/ containing lease/ (the verifier), client/ (activation for native hosts), examples and the JavaScript host SDK. Download lists everything in it.
Add Sigil to your project
Create the program (or open your own) beside the SDK and add the two crates as path dependencies:
$ cargo new my-engine
$ cd my-engine[dependencies]
sigil-lease = { path = "../sigil-sdk-rust-0.2.0/lease", features = ["std"] }
sigil-client = { path = "../sigil-sdk-rust-0.2.0/client" }Embed your application's keyset
Your binary must trust your application's public keys, and only those. Download the keyset with the button on the application's page in the portal, or fetch it. It's public, so no sign-in is needed:
$ curl -fsS https://sigil.enigmahq.sh/v1/client/apps/app_YOUR_APP_ID/keys -o sigil-keys.jsonCommit it with your code, and download it again for every release. It holds your active key and your standby key, so a build you ship today keeps working when you rotate. After a rotation, download it again so your next build carries the new standby.
Gate the protected code
Replace src/main.rs with the program below. The two lines that matter are include_bytes!("../sigil-keys.json"), which fixes trust at build time, and gate.require_now(FEATURE), which refuses unless a valid lease for this machine grants cosign. The rest is a small CLI around sigil-client.
//! A native program whose core only runs with a Sigil license.
//!
//! my-engine activate SGL-XXXXX-… take a seat on this machine, cache the lease
//! my-engine run [message] the protected work: refuses without a license
//! my-engine status what the gate sees, verified offline
//! my-engine deactivate release the seat
//!
//! Environment: SIGIL_API (default https://sigil.enigmahq.sh), SIGIL_STATE
//! (default ./.sigil).
use std::process::ExitCode;
use sigil_client::{Client, Config};
use sigil_lease::{Gate, Keyset};
// Downloaded from the portal (or GET /v1/client/apps/<app>/keys) and compiled
// in. This is where trust is fixed: the gate accepts leases signed by these
// keys and no others, whatever the host or the network says at run time.
static KEYS: &[u8] = include_bytes!("../sigil-keys.json");
// The entitlement the protected work needs: one of the policy's entitlements.
const FEATURE: &str = "cosign";
fn main() -> ExitCode {
let keyset = Keyset::parse(KEYS).expect("sigil-keys.json is a Sigil keyset");
let api = std::env::var("SIGIL_API").unwrap_or_else(|_| "https://sigil.enigmahq.sh".into());
let state = std::env::var("SIGIL_STATE").unwrap_or_else(|_| ".sigil".into());
let client = Client::new(Config::new(api, keyset.app(), state).app_version(env!("CARGO_PKG_VERSION")));
let mut gate = Gate::new(keyset);
let args: Vec<String> = std::env::args().skip(1).collect();
let result = match args.first().map(String::as_str) {
Some("activate") => match args.get(1) {
Some(key) => client.activate(key).map(|s| {
let l = s.license.expect("an online activation describes its license");
println!("✔ activated: {} · {} · seat {}/{}", l.name, l.entitlements.join(", "), l.machines_used, l.max_machines);
}),
None => {
eprintln!("usage: activate <license-key>");
return ExitCode::from(2);
}
},
Some("run") => client.unlock(&mut gate).and_then(|_| {
gate.require_now(FEATURE)?; // the check: inside this binary, against the keys above
let message = args.get(1).map(String::as_str).unwrap_or("hello");
println!("✔ running · {}", protected_work(message));
Ok(())
}),
Some("status") => client.unlock(&mut gate).map(|u| {
let c = &u.verified.claims;
println!("✔ {:?} · licensed to {} · {} · lease until {}", u.verified.status, c.lic, c.ent.join(", "), c.exp);
}),
Some("deactivate") => client.deactivate(Some(&mut gate)).map(|_| println!("✔ seat released")),
Some("fingerprint") => client.fingerprint().map(|fp| println!("{fp}")),
_ => {
eprintln!("commands: activate <key> | run [message] | status | deactivate | fingerprint");
return ExitCode::from(2);
}
};
match result {
Ok(()) => ExitCode::SUCCESS,
Err(e) => {
eprintln!("✖ not licensed: {e}");
ExitCode::from(3)
}
}
}
/// Stands in for the code worth protecting.
fn protected_work(message: &str) -> String {
let digest = message.bytes().fold(0xcbf2_9ce4_8422_2325u64, |h, b| (h ^ b as u64).wrapping_mul(0x0100_0000_01b3));
format!("co-signed \"{message}\" → {digest:016x}")
}In your own codebase, put the require call at the top of each protected entry point, with the feature that entry point needs.
Run it without a license
$ cargo run -q -- run
✖ not licensed: NOT_ACTIVATED: no license on this machine: activate a license key firstThe program builds and starts, but the protected work refuses. The same happens to anyone who copies the binary: without a lease signed for their machine, require fails.
https://sigil.enigmahq.sh by default. Set SIGIL_API=http://localhost:8787 to point it at a development server. Leases are cached in ./.sigil; set SIGIL_STATE to move them.Issue a license
In the portal, open Licenses → Issue license. Pick your application and the Engine policy, and name the licensee. Copy the key from the dialog. It's shown once, and Sigil stores only its hash.
SGL-7KQ2M-4WZ9P-R3T8X-B6N1C-H4X9DActivate and run
$ cargo run -q -- activate SGL-7KQ2M-4WZ9P-R3T8X-B6N1C-H4X9D
✔ activated: conFIEL Engine (prod) · cosign · seat 1/1
$ cargo run -q -- run "invoice 42"
✔ running · co-signed "invoice 42" → 7f3e1c0d2b9a4e61
$ cargo run -q -- status
✔ Valid · licensed to conFIEL Engine (prod) · cosign · lease until 1791234567Activation sent the license key and this machine's fingerprint to Sigil, took one seat, and cached a lease. From then on run works offline. The client renews the lease once it's past half its life, whenever the network is up.
See it in the portal
Open Installs. Your machine is listed as live on platform Server, with its hostname, version and lease expiry. The license's page shows the seat it holds, and Activity records Machine activated. From here you can release the seat or revoke the license. A revoked license stops at the install's next renewal, and the cached lease is dropped.
Next
- Protect a WASM module: the same gate in a
wasm32-unknown-unknownmodule, driven by@sigil/sdkfrom an extension or Node. - Using the portal: seats, revocation, air-gapped activation and key rotation.
- Rust SDK reference and lease protocol.