Skip to content

Declarations

Every circuit declares its inputs in the circuit signature. Each parameter specifies a visibilityPublic (visible to the verifier) or Witness (known only to the prover).

A circuit declaration names the circuit and lists its parameters with their visibility:

circuit multiply(output: Public, a: Witness, b: Witness) {
assert_eq(a * b, output)
}

Public inputs become part of the proof’s public statement — anyone verifying the proof can see their values. Witness inputs remain private to the prover.

Declare a fixed-size array of inputs with bracket syntax after the type:

circuit merkle_verify(root: Public, path: Witness Field[3], indices: Witness Bool[3]) {
// path and indices each have 3 elements
// access with standard indexing: path[0], path[1], path[2]
}

Array parameters create indexed variables that you access with standard indexing. They work for both public and witness inputs:

circuit commitment_check(commitments: Public Field[4], secrets: Witness Field[4]) {
for i in 0..4 {
assert_eq(poseidon(secrets[i], 0), commitments[i])
}
}

Parameters can include optional type annotations (Field or Bool) between the visibility and the parameter name (or array brackets):

circuit typed_example(root: Public Field, flag: Witness Bool) {
if flag {
assert_eq(root, poseidon(root, 0))
}
}

For array parameters, the type goes between the visibility and the brackets:

circuit merkle_path(root: Public Field, path: Witness Field[3], indices: Witness Bool[3]) {
// indices are boolean-typed, saving 1 constraint each
}

Annotating a witness as Bool saves 1 constraint by skipping boolean enforcement. See Type Annotations for full details.

Inside the circuit body, parameters are ordinary variables. Use them in expressions, pass them to builtins, and index into arrays:

circuit product_check(output: Public, a: Witness, b: Witness) {
let product = a * b
assert_eq(product, output)
let sum = a + b
assert_eq(sum, a + b)
}

Array elements are accessed by index:

circuit sum_check(expected_sum: Public, vals: Witness Field[3]) {
let acc = vals[0]
let acc = acc + vals[1]
let acc = acc + vals[2]
assert_eq(acc, expected_sum)
}

Pass concrete values for circuit inputs with the --inputs flag:

Terminal window
ach circuit program.ach --inputs "a=3,b=5,output=15"

Array inputs are passed with indexed names:

Terminal window
ach circuit merkle.ach --inputs "root=123,leaf=42,path_0=99,path_1=77,indices_0=0,indices_1=1"
ErrorCause
DuplicateInputSame name declared twice in the parameter list
UndeclaredVariableUsing a variable inside the circuit body that is not a parameter
AnnotationMismatchDeclared type doesn’t match the inferred type