Witnesses
In a constraint system, a witness is kind of like a blank space that is purposefully left to be filled in by the prover. The size and shape of a witness must be known at compile time, but the value does not need to be known until the prover generates a proof.
Witnesses are useful because they allow you to "witness in" arbitrary data into a proof. A classic use case is to compute square
root. It is trivial to prove that x * x = y
, and it is not trivial to prove that x = sqrt(y)
. Using a witness, we can use
the triviality of multiplication to prove square root.
const x = 10;
// unconstrained value of type UInt32
const w_sqrt = Provable.witness(UInt32, () => {
return UInt32.from(x);
});
// constraint added to w_sqrt to prove that it satisfies the square root function
w_sqrt.mul(w_sqrt).assertEquals(UInt32.from(100));