Skip to main content

The Contract

pragma language_version >= 0.23;

import CompactStandardLibrary;

// Unsigned integers - bounded type
export ledger counter: Uint<0..1000>;

// Unsigned integers - sized type (32 bits)
export ledger balance: Uint<32>;

// Field element for ZK computations
export ledger commitment: Field;

// Fixed-length byte array
export ledger hash: Bytes<32>;

// Opaque type - hashed inside circuits, full value visible off-chain
export ledger secretValue: Opaque<"string">;

export circuit updateCounter(newValue: Uint<0..1000>): [] {
  counter = disclose(newValue);
}

export circuit updateBalance(amount: Uint<32>): [] {
  // a + b widens; assert no overflow, then cast back to Uint<32>
  assert(balance <= (4294967295 as Uint<32>) - amount, "balance overflow");
  balance = disclose((balance + amount) as Uint<32>);
}

export circuit storeCommitment(value: Field): [] {
  commitment = disclose(value);
}

export circuit storeHash(data: Bytes<32>): [] {
  hash = disclose(data);
}

export circuit updateSecret(secret: Opaque<"string">): [] {
  secretValue = disclose(secret);
}

How It Works

Unsigned Integer Types - Bounded

export ledger counter: Uint<0..1000>;
Uint<m..n> represents values from m to n (inclusive). Lower bound must be 0.

Unsigned Integer Types - Sized

export ledger balance: Uint<32>;
Uint<n> uses up to n bits, equivalent to Uint<0..(2^n - 1)>. The maximum width is Uint<248>.

Field Type

export ledger commitment: Field;
Elements of the scalar prime field used by the ZK proof system. Arithmetic on Field wraps modulo the prime. Comparison operators (<, <=) are not defined on Field; convert to a Uint first if you need ordering.

Bytes Type

export ledger hash: Bytes<32>;
Fixed-length byte arrays. Bytes<n> for exactly n bytes.

Opaque Types

export ledger secretValue: Opaque<"string">;
Opaque<"label"> is a value whose internal representation is opaque to circuit logic: the circuit can hash it, store it, and pass it around, but cannot read or branch on its contents. The witness layer holds the real bytes; the ZK proof commits to the hash.

Disclosure Rule for Circuit Parameters

counter = disclose(newValue);
Compact’s privacy model is conservative: any circuit parameter is treated as potentially witness-derived at compile time. Writing a parameter directly to ledger state without disclose() fails with:
potential witness-value disclosure must be declared but is not
This applies to every type — Uint, Field, Bytes, and Opaque alike. disclose(x) is a compiler annotation that says “I know this value flows from a (potentially) private source to a public location and that’s intentional.” See Privacy & Disclosure for more on the disclosure rule.

Arithmetic Widening and Casts

Compact has no silent overflow. Arithmetic on bounded integers produces a wider result type:
balance = disclose((balance + amount) as Uint<32>);   // assert first, then cast
See Overflow Protection for the full pattern.

Boolean Type

export ledger flag: Boolean;
Two values: true and false. Standard operators: &&, ||, !, ==, !=.

What’s Next

Hello World

Apply types in your first contract

First App

Build a counter with type safety