Std
We're supporting some standard circuits in our std library, all of which will implement the following trait:
pub trait StdCircuit<C: Config>: Clone + Define<C> + DumpLoadTwoVariables<Variable> {
type Params: Clone + Debug;
type Assignment: Clone + DumpLoadTwoVariables<C::CircuitField>;
fn new_circuit(params: &Self::Params) -> Self;
fn new_assignment(params: &Self::Params, rng: impl RngCore) -> Self::Assignment;
}
Params
refers to the parameters used to define a circuit. For example, to build a Merkle Tree circuit, we need to know what's the depth of the tree, and which hash function to use.Assignment
refers to the assignment of the private and public input, represented as field elements. In the Merkle Tree example, if we're checking the membership of a leaf, the assignment will consist of the root hash, the leaf hash, and the Merkle path.new_circuit
will return a circuit according toparams
. Note that there are no concrete values in the returned circuit, all variables are placeholders, faciliting the compilation of the circuit structure.new_assignment
, as the name suggests, returns a group of correct assignment.
Example usage
We create a circuit_test_helper
in our std library, which can be referred to as an example.
use circuit_std_rs::StdCircuit;
use expander_compiler::frontend::*;
use extra::Serde;
use rand::thread_rng;
pub fn circuit_test_helper<Cfg, Cir>(params: &Cir::Params)
where
Cfg: Config,
Cir: StdCircuit<Cfg>,
{
let mut rng = thread_rng();
let compile_result: CompileResult<Cfg> = compile(&Cir::new_circuit(¶ms)).unwrap();
let assignment = Cir::new_assignment(¶ms, &mut rng);
let witness = compile_result
.witness_solver
.solve_witness(&assignment)
.unwrap();
let output = compile_result.layered_circuit.run(&witness);
assert_eq!(output, vec![true]);
}
Cfg
here can be one of BN254Config, M31Config, GF2Config
, and all circuits in the std library can be used as Cir
.
Supported Circuits
LogUp. A circuit attesting to the correctness of table look up.