| Crates.io | ark-feanor |
| lib.rs | ark-feanor |
| version | 0.7.1 |
| created_at | 2025-10-16 09:09:25.256441+00 |
| updated_at | 2025-11-20 14:06:25.636887+00 |
| description | Bridge between arkworks finite fields and feanor-math ring system |
| homepage | |
| repository | https://github.com/vitorpy/ark-feanor |
| max_upload_size | |
| id | 1885651 |
| size | 14,707,760 |
A bridge between arkworks' finite field types and feanor-math's ring system.
ark-feanor enables you to use feanor-math's advanced polynomial and Gröbner basis algorithms with arkworks' cryptographic field implementations. This is particularly useful for:
PrimeField typesAdd this to your Cargo.toml:
[dependencies]
ark-feanor = "0.1"
use ark_feanor::*;
// Use pre-configured BN254 scalar field
let field = &*BN254_FR;
let a = field.int_hom().map(5);
let b = field.int_hom().map(3);
let c = field.add(a, b);
assert_eq!(field.int_hom().map(8), c);
// Or create your own wrapper
use ark_bn254::Fr;
let my_field = ArkFieldWrapper::<Fr>::new();
let x = my_field.from_int(10);
let y = my_field.from_int(20);
let z = my_field.mul_ref(&x, &y);
use ark_feanor::*;
use feanor_math::rings::poly::dense_poly::DensePolyRing;
use feanor_math::rings::poly::PolyRingStore;
// Create univariate polynomial ring BLS12-381_Fr[x]
let field = &*BLS12_381_FR;
let poly_ring = DensePolyRing::new(field.clone(), "x");
// Create polynomial: 3x² + 2x + 1
let poly = poly_ring.from_terms([
(field.int_hom().map(1), 0), // 1
(field.int_hom().map(2), 1), // 2x
(field.int_hom().map(3), 2), // 3x²
].iter().cloned());
// Evaluate at x = 5
let result = poly_ring.evaluate(&poly, &field.int_hom().map(5), &field.identity());
use ark_feanor::*;
use ark_feanor::f4::*;
use feanor_math::rings::multivariate::*;
// Create multivariate ring BN254_Fr[x, y]
let field = &*BN254_FR;
let poly_ring = MultivariatePolyRingImpl::new(field, 2);
// Define polynomial system:
// x² + y² - 1 = 0
// xy - 2 = 0
let system = poly_ring.with_wrapped_indeterminates(|[x, y]| {
vec![
x.clone().pow(2) + y.clone().pow(2) - 1,
x.clone() * y.clone() - 2,
]
});
// Compute Gröbner basis using F4
let gb = f4_simple(&poly_ring, system, DegRevLex);
println!("Basis has {} polynomials", gb.len());
The library provides convenient access to commonly used cryptographic fields:
BN254:
BN254_FR / BN254ScalarField: Scalar field (Fr)BN254_FQ / BN254BaseField: Base field (Fq)BLS12-381:
BLS12_381_FR / BLS12_381ScalarField: Scalar field (Fr)BLS12_381_FQ / BLS12_381BaseField: Base field (Fq)Any arkworks field implementing Field or PrimeField can be wrapped:
use ark_feanor::ArkFieldWrapper;
use ark_bw6_761::Fr;
let field = ArkFieldWrapper::<Fr>::new();
Check out the examples/ directory for complete working examples:
simple_groebner.rs: Basic Gröbner basis computationpolynomial_system.rs: Solving polynomial systemsRun examples with:
cargo run --example simple_groebner
The wrapper is designed for minimal overhead. Benchmarks show:
Run benchmarks with:
cargo bench
When working with multivariate polynomial rings with many variables (e.g., 1000+), memory usage grows exponentially due to monomial counts. The optional multiplication table in MultivariatePolyRingImpl::new_with_mult_table() can significantly impact memory requirements.
Key constraints:
n variables at degree d: binomial(n + d - 1, d)Σ(lhs_deg, rhs_deg) monomials(lhs_deg) × monomials(rhs_deg) × 8 bytesExample: 1142 variables
| Config | Memory | Notes |
|---|---|---|
| (0, 0) | 8 B | No multiplication table (safest) |
| (1, 1) | 10 MB | Minimal caching |
| (1, 2) | 5.57 GB | Optimal for 50-100GB budgets |
| (0, 3) | 1.86 GB | Alternative lower-memory option |
| (2, 2) | 3.11 TB | Impractical - exponential cliff |
Recommended configurations:
use ark_feanor::*;
use feanor_math::rings::multivariate::*;
let field = &*BN254_FR;
// Best performance within reasonable memory (5.57 GB)
let poly_ring = MultivariatePolyRingImpl::new_with_mult_table(
field.clone(),
1142, // variables
7, // max degree (u64 limit)
(1, 2), // optimal for 50-100GB budgets
std::alloc::Global
);
// Lower memory footprint (1.86 GB)
let poly_ring = MultivariatePolyRingImpl::new_with_mult_table(
field.clone(),
1142,
7,
(0, 3), // alternative if memory is tighter
std::alloc::Global
);
// Minimal memory, no multiplication table
let poly_ring = MultivariatePolyRingImpl::new_with_mult_table(
field.clone(),
1142,
7,
(0, 0), // no caching, slower but safe
std::alloc::Global
);
Performance vs. Memory Trade-off:
The multiplication table caches products of basis monomials. Configurations like (1, 2) cache products of degree-1 monomials with degree-2 monomials, speeding up polynomial multiplication at the cost of ~5-6 GB RAM.
For smaller variable counts (< 100), the default configuration (6, 8) works well. For large constraint systems (1000+ variables), use (1, 2) or (0, 0) to avoid memory exhaustion.
Why the exponential cliff?
At degree 2 with 1142 variables: 652,653 monomials
(1, 2): 1,142 × 652,653 × 8 bytes = 5.57 GB ✓(2, 2): 652,653 × 652,653 × 8 bytes = 3.11 TB ✗The binomial coefficient growth makes degree-2 tables impractical beyond ~100 variables.
The library is organized into several modules:
field_wrapper: Core RingBase trait implementationprime_field: Specialized traits for prime fields (division, etc.)conversions: Type conversions between arkworks and feanor-mathhomomorphisms: Ring homomorphisms and embeddingscommon_fields: Pre-configured field typesPrimeField typesContributions are welcome! Please feel free to submit issues and pull requests.
# Run tests
cargo test
# Run with all features
cargo test --all-features
# Check documentation
cargo doc --open
# Run clippy
cargo clippy -- -D warnings
Licensed under either of
at your option.