Working with auto-generated Cairo Code

Developer workflow

If working with the python - auto generated cairo code, the main script to work with is make rewrite \

tools/make/rewrite.sh
rm -rf src/src/tests/*
rm -rf src/src/circuits/*
rm -rf src/contracts/groth16_example_bls12_381/*
rm -rf src/contracts/groth16_example_bn254/*
rm -rf src/contracts/risc0_verifier_bn254/*

set -e  # Exit immediately if a command exits with a non-zero status

python hydra/garaga/precompiled_circuits/all_circuits.py || { echo "Error in all_circuits.py"; exit 1; }
python hydra/garaga/starknet/tests_and_calldata_generators/test_writer.py || { echo "Error in test_writer.py"; exit 1; }
python hydra/garaga/starknet/groth16_contract_generator/generator.py || { echo "Error in generator.py"; exit 1; }
python hydra/garaga/starknet/groth16_contract_generator/generator_risc0.py || { echo "Error in generator_risc0.py"; exit 1; }

As you can see this will :

  • Rewrite all the auto-generated cairo code in src/src/circuits/ (with the all_circuits.py script)

  • Rewrite all the auto-generated cairo tests in src/src/tests/ (with the test_writer.py script)

  • Rewrite the Groth16 verifiers smart contract templates examples in src/contracts/ (with the generator.py and generator_risc0.py scripts)

Creating auto-generated circuits.

While it's relatively easy to write Cairo circuits yourself if their size is small, it starts to be quite time consuming if you need to build a large amount of them, parametrize them, and the circuits themselves are quite large.

Examples of small hand-made small circuits can be found in https://github.com/keep-starknet-strange/garaga/blob/main/src/src/basic_field_ops.cairo

If you want to write a new auto-generated circuit to src/src/circuits, you can define them with python code, and register them to the all_circuits.py file. Below we show a basic tutorial for a non-parametrized circuit.

Simple isolated example

To obtain the corresponding Cairo code, you can do it like this

The obtained Cairo code will be

Note that the compiler will adapt the signature of the Cairo function depending on the generic_circuit parameter, and retrieve the corresponding modulus inside the function code.

Using parameterization (docs in progress 🚧)

The base class

Currently, the way we deal with parameterization is encapsulating the earlier ModuloCircuit class into a BaseModuloCircuit class, and adding keyword arguments to the class deriving it.

All Cairo function must inherit from the base abstract class The abstract methods to implement are : \

  • build_input

  • _run_circuit_inner

At initialization, you must choose a name for the circuit. Pay attention to the parameter generic_circuit passed to the ModuloCircuit class inside _run_circuit_inner

Last updated

Was this helpful?