risc0-core
The risc0-core crate provides fundamental components shared across RISC Zero crates, most notably finite field implementations and field arithmetic.
Installation
[dependencies]
risc0-core = "1.3.0"
Overview
This is a foundational crate containing:
- Finite field implementations (Baby Bear, Goldilocks)
- Field element types and traits
- Random number generation for fields
- Performance profiling utilities
This is a low-level crate. Most users should use higher-level crates like risc0-zkvm.
Feature Flags
Enables standard library support.
Enables performance profiling with NVTX and Puffin.
Field Module
Finite field implementations and traits.pub mod field {
pub mod baby_bear;
pub mod goldilocks;
}
Field Traits
Elem
Base trait for field elements.pub trait Elem:
Copy
+ Clone
+ Default
+ PartialEq
+ Eq
+ Add<Output = Self>
+ Sub<Output = Self>
+ Mul<Output = Self>
+ AddAssign
+ SubAssign
+ MulAssign
{
const ZERO: Self;
const ONE: Self;
const INVALID: Self;
fn random(rng: &mut impl RngCore) -> Self;
fn inv(&self) -> Self;
fn pow(&self, exp: usize) -> Self;
}
ExtElem
Extension field element trait.pub trait ExtElem:
Elem
{
const EXT_SIZE: usize;
type SubElem: Elem;
fn from_subelems(elems: impl IntoIterator<Item = Self::SubElem>)
-> Self;
fn subelems(&self) -> &[Self::SubElem];
}
Baby Bear Field
Baby Bear prime field implementation.pub mod baby_bear {
pub type BabyBearElem;
pub type BabyBearExtElem;
}
Prime: p = 2^31 - 2^27 + 1 = 2,013,265,921Properties:
- 31-bit prime field
- Efficient modular arithmetic
- 4-element extension field
- Optimized for modern CPUs
BabyBearElem
Baby Bear field element.pub struct BabyBearElem(u32);
impl BabyBearElem {
pub const fn new(val: u32) -> Self;
pub fn as_u32(&self) -> u32;
pub fn from_u32(val: u32) -> Self;
}
Example:use risc0_core::field::baby_bear::BabyBearElem;
let a = BabyBearElem::new(42);
let b = BabyBearElem::new(17);
let c = a + b;
assert_eq!(c.as_u32(), 59);
BabyBearExtElem
Baby Bear extension field element (degree 4).pub struct BabyBearExtElem([BabyBearElem; 4]);
impl BabyBearExtElem {
pub const ZERO: Self;
pub const ONE: Self;
pub fn from_subelems(elems: [BabyBearElem; 4]) -> Self;
pub fn subelems(&self) -> &[BabyBearElem; 4];
}
Example:use risc0_core::field::baby_bear::{BabyBearElem, BabyBearExtElem};
use risc0_core::field::{Elem, ExtElem};
let a = BabyBearElem::new(1);
let b = BabyBearElem::new(2);
let c = BabyBearElem::new(3);
let d = BabyBearElem::new(4);
let ext = BabyBearExtElem::from_subelems([a, b, c, d]);
Goldilocks Field
Goldilocks prime field implementation.pub mod goldilocks {
pub type GoldilocksElem;
}
Prime: p = 2^64 - 2^32 + 1Properties:
- 64-bit prime field
- Excellent for 64-bit architectures
- Fast modular reduction
Random Number Generation
Generate random field element.use risc0_core::field::baby_bear::BabyBearElem;
use risc0_core::field::Elem;
use rand::thread_rng;
let mut rng = thread_rng();
let random_elem = BabyBearElem::random(&mut rng);
Performance profiling utilities.Integrates with:
- NVTX: NVIDIA profiling for CUDA
- Puffin: Rust profiling framework
Profiling Macros
#[cfg(feature = "perf")]
use risc0_core::perf::profile_scope;
fn expensive_operation() {
profile_scope!("expensive_operation");
// ... code to profile
}
Field Arithmetic
Basic Operations
use risc0_core::field::baby_bear::BabyBearElem;
let a = BabyBearElem::new(10);
let b = BabyBearElem::new(20);
// Addition
let sum = a + b;
// Multiplication
let product = a * b;
// Subtraction
let diff = a - b;
// Inversion (multiplicative inverse)
let inv = a.inv();
assert_eq!(a * inv, BabyBearElem::ONE);
Power and Exponentiation
use risc0_core::field::baby_bear::BabyBearElem;
use risc0_core::field::Elem;
let a = BabyBearElem::new(2);
let result = a.pow(10); // 2^10 mod p
Extension Field Operations
use risc0_core::field::baby_bear::{BabyBearElem, BabyBearExtElem};
use risc0_core::field::{Elem, ExtElem};
let a = BabyBearExtElem::from_subelems([
BabyBearElem::new(1),
BabyBearElem::new(2),
BabyBearElem::new(3),
BabyBearElem::new(4),
]);
let b = BabyBearExtElem::from_subelems([
BabyBearElem::new(5),
BabyBearElem::new(6),
BabyBearElem::new(7),
BabyBearElem::new(8),
]);
let sum = a + b;
let product = a * b;
Batch Operations
use risc0_core::field::baby_bear::BabyBearElem;
use risc0_core::field::Elem;
fn batch_mul(elems: &[BabyBearElem]) -> BabyBearElem {
elems.iter().fold(BabyBearElem::ONE, |acc, &x| acc * x)
}
fn batch_add(elems: &[BabyBearElem]) -> BabyBearElem {
elems.iter().fold(BabyBearElem::ZERO, |acc, &x| acc + x)
}
Conversion and Serialization
use risc0_core::field::baby_bear::BabyBearElem;
// To/from u32
let elem = BabyBearElem::new(42);
let value: u32 = elem.as_u32();
let elem2 = BabyBearElem::from_u32(value);
assert_eq!(elem, elem2);
// Bytemuck support (zero-copy)
use bytemuck::{Pod, Zeroable};
let bytes: &[u8] = bytemuck::bytes_of(&elem);
let elem_ref: &BabyBearElem = bytemuck::from_bytes(bytes);
Constants
use risc0_core::field::baby_bear::BabyBearElem;
use risc0_core::field::Elem;
assert_eq!(BabyBearElem::ZERO.as_u32(), 0);
assert_eq!(BabyBearElem::ONE.as_u32(), 1);
// INVALID is used for uninitialized/error states
let invalid = BabyBearElem::INVALID;
Field Properties
Baby Bear
| Property | Value |
|---|
| Prime | 2^31 - 2^27 + 1 |
| Bits | 31 |
| Extension Degree | 4 |
| Primitive Root | 31 |
| Two-Adicity | 27 |
Goldilocks
| Property | Value |
|---|
| Prime | 2^64 - 2^32 + 1 |
| Bits | 64 |
| Two-Adicity | 32 |
Field operations are highly optimized:
- SIMD: Vectorized operations on CPU
- GPU: Parallel field operations on CUDA/Metal
- Zero-copy: Bytemuck integration for efficient memory access
Benchmarks (typical)
| Operation | Time (ns) |
|---|
| Addition | ~1 |
| Multiplication | ~2 |
| Inversion | ~100 |
| Extension Mul | ~10 |
Examples
Polynomial Evaluation
use risc0_core::field::baby_bear::BabyBearElem;
use risc0_core::field::Elem;
fn eval_poly(coeffs: &[BabyBearElem], x: BabyBearElem) -> BabyBearElem {
coeffs.iter().rev().fold(BabyBearElem::ZERO, |acc, &coeff| {
acc * x + coeff
})
}
let coeffs = [
BabyBearElem::new(1),
BabyBearElem::new(2),
BabyBearElem::new(3),
];
let x = BabyBearElem::new(5);
let result = eval_poly(&coeffs, x); // 3*5^2 + 2*5 + 1 = 86
Matrix Multiplication
use risc0_core::field::baby_bear::BabyBearElem;
use risc0_core::field::Elem;
fn mat_vec_mul(
matrix: &[Vec<BabyBearElem>],
vector: &[BabyBearElem],
) -> Vec<BabyBearElem> {
matrix
.iter()
.map(|row| {
row.iter()
.zip(vector)
.map(|(&a, &b)| a * b)
.fold(BabyBearElem::ZERO, |acc, x| acc + x)
})
.collect()
}
Thread Safety
Field elements are Copy and Send + Sync, making them safe for concurrent use:
use risc0_core::field::baby_bear::BabyBearElem;
use rayon::prelude::*;
fn parallel_square(elems: &[BabyBearElem]) -> Vec<BabyBearElem> {
elems.par_iter().map(|&x| x * x).collect()
}
Links