Skip to main content

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

std
feature
Enables standard library support.
perf
feature
Enables performance profiling with NVTX and Puffin.

Field Module

field
module
Finite field implementations and traits.
pub mod field {
    pub mod baby_bear;
    pub mod goldilocks;
}

Field Traits

Elem

Elem
trait
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

ExtElem
trait
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
module
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

BabyBearElem
struct
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

BabyBearExtElem
struct
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
module
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

random
trait method
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 (with perf feature)

perf
module
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

PropertyValue
Prime2^31 - 2^27 + 1
Bits31
Extension Degree4
Primitive Root31
Two-Adicity27

Goldilocks

PropertyValue
Prime2^64 - 2^32 + 1
Bits64
Two-Adicity32

Performance

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)

OperationTime (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()
}

Build docs developers (and LLMs) love