The Two Worlds
Console Types: Native Execution
Console types insnarkvm-console-types execute natively on the CPU using standard Rust field arithmetic:
- Fast native arithmetic (nanoseconds per operation)
- Direct field element manipulation
- No constraint generation overhead
- Used for transaction verification and plaintext evaluation
Circuit Types: Constraint Generation
Circuit types insnarkvm-circuit-types generate R1CS constraints for proof generation:
- Each operation generates R1CS constraints
- Variables tracked in constraint system
- Three modes:
Constant,Public,Private - Used for proof generation during program execution
Synchronization Requirement
FromAGENTS.md:25:
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.
Why Synchronization Matters
Consider a transaction that transfers tokens:- Local Execution: User runs console types to verify the transaction works
- Proof Generation: Synthesizer runs circuit types to generate a SNARK proof
- Network Verification: Validators run console types to verify the proof
- User sees valid transaction locally
- Proof generation succeeds with different values
- Validators reject the transaction
- Result: Consensus fork and network partition
Type Correspondence
Every console type has an exact circuit equivalent:Module Mirroring
Both crate families have identical structure:Inject and Eject Traits
Circuit types implement two key traits for converting between console and circuit representations:Inject: Console → Circuit
Mode::Constant: Value is compile-time constant, no variable allocatedMode::Public: Value is public input, allocated as public variableMode::Private: Value is private witness, allocated as private variable
circuit/types/field/src/lib.rs:67):
Eject: Circuit → Console
circuit/types/field/src/lib.rs:76):
Constraint Generation
Linear Combinations
Circuit types internally represent values as linear combinations of variables:2*a + 3*b + 5 is represented as:
R1CS Constraints
Operations enforce constraints in the formA * B = C where A, B, C are linear combinations:
c = a * b generates:
Operation Examples
Addition
Console (fromconsole/types/field/src/arithmetic.rs):
circuit/types/field/src/add.rs):
Field addition is “free” in circuits - it doesn’t generate constraints because linear combinations can be combined directly.
Multiplication
Console (fromconsole/types/field/src/arithmetic.rs):
circuit/types/field/src/mul.rs):
Field multiplication generates 1 R1CS constraint. This is the fundamental cost unit for circuit complexity.
Comparison
Console (fromconsole/types/field/src/compare.rs):
circuit/types/field/src/equal.rs):
- Compute
diff = a - b - Check
diff == 0using inverse computation - Generates multiple constraints for zero-check
Testing Equivalence
Circuit types include tests that verify equivalence with console types:- Circuit operations produce same results as console
- All input combinations are tested
- Edge cases (zero, max, negative) are covered
Program Execution Flow
Performance Implications
Console Execution
- Speed: Native CPU instructions, ~nanoseconds per operation
- Use Cases: Transaction validation, blockchain state queries, proof verification
- Memory: Minimal overhead, direct field elements
Circuit Execution
- Speed: Constraint generation ~microseconds, proving ~milliseconds to seconds
- Use Cases: Proof generation for transactions and programs
- Memory: Stores entire constraint system (can be gigabytes for large programs)
Best Practices
For SnarkVM Contributors
- Always modify both: When changing console types, update circuit types identically
- Test equivalence: Add tests comparing console and circuit outputs
- Document constraints: Note how many constraints each operation generates
- Avoid divergence: Never add console-only or circuit-only behavior
For Aleo Program Developers
- Understand cost model: Multiplications are expensive, additions are free
- Minimize constraints: Refactor to reduce circuit operations
- Test locally: Use console mode for rapid iteration
- Profile circuits: Measure constraint counts for performance tuning
Common Pitfalls
Other issues to avoid:- Floating point: No floating point types exist; use fixed-point field arithmetic
- Overflow: Integer types wrap by default; use checked operations for safety
- Randomness: Circuit randomness must come from witness, not generated internally
- Serialization: Ensure deterministic serialization for consensus
Next Steps
Zero-Knowledge Proofs
Learn how circuits become SNARKs
Architecture
Explore the full crate structure