Compiler hints
Instead of computing some value within a circuit, it's sometimes more optimal to compute the value off-circuit and only verify the correctness of the computation in a circuit. gnark
allows you to do this through hints. From the prover's point of view, hints are essentially input variables provided by a hint function instead of the user.
For example, consider a decomposition of an integer a
into bits. A naive way to decompose it is to look at the binary representation of the integer and extract bits from this representation, but gnark
doesn't currently provide native bit operations. Instead, the hint function hint.IthBit
can provide the bits as variables and the user must constrain these variables as a weighted sum which equals to a
. In a circuit it would look like:
var b []frontend.Variable
var Σbi frontend.Variable
base := 1
for i := 0; i < nBits; i++ {
b[i] = cs.NewHint(hint.IthBit, a, i)
cs.AssertIsBoolean(b[i])
Σbi = api.Add(Σbi, api.Mul(b[i], base))
base = base << 1
}
cs.AssertIsEqual(Σbi, a)
This method is also implemented in the front end as ToBinary(...)
interface method.
gnark
provides a list of built-in hint functions.
Implement hint functions
You can define your own hint functions in addition to built-in hint functions. You can provide any instance satisfying the hint.Function
to api.NewHint(...)
method to compute the hint value. Additionally, you must provide the hint function as a backend.WithHints
option to the back end, so the back end can access the hint function.
gnark
also provides a constructor hint.NewStaticHint
for constructing simple hint functions, which takes a constant number of inputs and returns a constant number of outputs.