- Search for existing implementations.
- Read the target module and match its patterns exactly.
- Scope out necessary tests ahead of time.
- If uncertain, ask.
- Think very hard in your planning process.
- New files, crates, dependencies, abstractions, traits, or error types require approval.
snarkVM is a virtual machine for zero-knowledge proof execution on the Aleo blockchain.
Crate dependencies:
snarkvm-utilities- no deps, macros and parallel primitivessnarkvm-fields- depends on utilities, finite field arithmeticsnarkvm-curves- depends on fields, elliptic curve implementationssnarkvm-algorithms- depends on curves/fields, cryptographic primitives (Poseidon, Marlin, Polycommit)snarkvm-console- depends on algorithms, plaintext VM types (Address, Field, Group, Scalar, programs)snarkvm-circuit- depends on console, circuit/constraint equivalents of console typessnarkvm-ledger- depends on synthesizer, blockchain state (blocks, transactions, storage)snarkvm-synthesizer- depends on console/circuit/algorithms, program execution and proof generation
console / circuit sync requirement:
- These crate families must stay in sync. Same structure, same API.
- When modifying one, check the other.
- Test circuit equivalence by comparing constraint counts.
- All changes must be backwards compatible — no consensus forks.
- New files, crates, dependencies, abstractions, or traits require approval.
unwraps must have a comment justifying why they can't panic.
There are deployed versions of this software in the wild. Changes that alter consensus behavior (same inputs producing different outputs) will fork the network. All changes must either be backwards compatible or gated behind a consensus version so they can be rolled in at the appropriate time. Not all code has been released publicly, so if you are unsure whether a change is safe on a PR, ask before proceeding.
- Test-driven development: write failing tests first.
unwraps must be commented with justification.- Prefer
zip_eqoverzipwhen lengths must match. - Pre-allocate with
with_capacitywhen final size is known. - Prefer
into_iter()overiter().cloned(). Prefer references over.clone(). - Use iterators; avoid intermediate
.collect()when a single pass follows. - Trait impls (ToBits, FromBits, ToField, FromField) should follow existing patterns in the same file.
See @CONTRIBUTING.md for detailed memory and performance guidelines.
Synthesizer tests are slow — run only the specific test function.
Use --features test,dev_println for integration tests.
cargo test -p <crate> # Run crate tests
cargo test -p <crate> -- test_name # Run specific test
cargo test -p snarkvm-synthesizer --features test,dev_println # Integration testsRun in order:
cargo check -p <crate>
cargo clippy -p <crate> -- -D warnings
cargo +nightly fmt --check
cargo test -p <crate>Clippy warnings are errors. Formatting requires nightly (cargo +nightly fmt --all to fix).
Pre-commit hook runs workspace-wide: cargo clippy --workspace --all-targets --all-features -- -D warnings && cargo +nightly fmt --all -- --check
- Never commit unless explicitly asked.
- Stage with
git addonly if requested. - Run
cargo +nightly fmt --allbefore staging.
- One blank line between functions.
- No trailing whitespace.
- Imports: std first, external crates second, crate-local third.
- Match existing file patterns exactly — if the file uses
Self::, you useSelf::. - Comments must be concise, complete, punctuated sentences.
#![forbid(unsafe_code)]in all crates unless approved.- License header required (enforced by
build.rs).
- Logic traced step-by-step.
- Boundary conditions handled: zero, empty, max, off-by-one.
- Error handling correct; no panics in production paths.
- Serialization/deserialization roundtrips verified.
- Field operations use checked arithmetic where needed.
- Randomness sources are cryptographically secure.
- No consensus-breaking changes (same inputs must produce same outputs).
- Circuit constraints match console logic exactly.
- Proof verification logic is sound.
- No unnecessary allocations in hot paths.
- Pre-allocation with
with_capacitywhere size known. - No unnecessary
.clone()— prefer references. - Iterators used efficiently; no intermediate collections.
- Parallel execution with rayon where appropriate.
- Input validation at trust boundaries.
- No information leakage in error messages.
- Fail-closed (reject on uncertainty).
- Start from program input.
- Follow through console types -> circuit synthesis -> proof generation.
- Track field element transformations.
- Verify output matches expected proof/execution result.
For each operation, ask:
- What if input is zero/empty/max?
- What if field elements overflow?
- What if serialization format changes?
- What if circuit constraints don't match console logic?
- Console and circuit types produce identical outputs for identical inputs.
- Serialization is deterministic and backwards compatible.
- Proof verification succeeds for valid proofs and fails for invalid ones.
- All randomness is derived from cryptographically secure sources.