Pure Circuits

A circuit is considered pure if it computes its outputs from its inputs without reference to or modification of public state (via the ledger) or private state (via witnesses).

Source: Circuits

Syntax

The pure modifier must follow export (if present):

pure circuit helper(x: Field): Field {
    return x * 2;
}

export pure circuit publicHelper(x: Field): Field {
    return x * 2;
}

If a pure circuit actually uses ledger operations or witnesses, the compiler rejects it. Marking a circuit pure ensures it appears in the generated PureCircuits type and pureCircuits constant in the TypeScript output.

Source: Circuits, TypeScript target

What Makes a Circuit Impure?

According to the docs, the compiler considers a circuit to be impure if:

  1. The body contains a ledger operation
  2. The body calls any impure circuit
  3. The body calls a witness

Note: Some standard library functions are witnesses and make the caller impure.

What Pure Circuits Can Do

  • ✅ Perform calculations
  • ✅ Call other pure circuits
  • ✅ Call pure standard library functions
  • ✅ Use parameters and local variables
  • ❌ Read ledger state
  • ❌ Modify ledger state
  • ❌ Call witnesses
  • ❌ Call impure circuits

Use Cases

Mathematical Operations

pure circuit triple(amount: Uint<64>): Uint<64> {
    return (amount * 3) as Uint<64>;
}

⚠️ Note: Compact has no division operator — / is a parse error. Percentage-style math (e.g., a 3% fee) can’t be written as amount * 3 / 100; compute the quotient off-chain, pass it in as a witness, and constrain it in the circuit (see Chapter 7: Witnesses).

Validation Logic

pure circuit isValidAge(age: Uint<8>): Boolean {
    return age >= 18 && age <= 120;
}

Type Conversions

pure circuit toBytes(value: Uint<64>): Bytes<32> {
    return (value as Field) as Bytes<32>;
}

Using Pure Circuits

Call pure circuits from any circuit:

export ledger counter: Counter;

pure circuit validate(x: Uint<64>): Boolean {
    return x > 0 && x < 1000;
}

export circuit process(amount: Uint<64>): [] {
    assert(validate(amount), "Invalid amount");
    counter.increment(disclose(amount as Uint<16>));
}

TypeScript Integration

The Compact compiler exports pure circuits via pureCircuits in the TypeScript module, allowing them to be used directly without blockchain interaction.

Source: TypeScript target

Benefits of Pure Circuits

  1. Verification - Compiler enforces purity constraints
  2. Reusability - Share logic across circuits
  3. Off-chain use - Available via pureCircuits in TypeScript
  4. Clarity - Clear separation of stateful vs stateless logic

Exercises

Complete exercises/03_circuits/04_pure_circuits/.