Skip to content

Commit 07a8896

Browse files
markosg04moodlezoupclaude
authored
feat: add Jolt witness crate (#1604)
* feat: add Jolt witness crate Introduce the jolt-witness crate: the witness-generation layer producing committed and virtual polynomials for the Jolt VM, dory-assist, wrapper, and blindfold protocols. Consolidates follow-up refactors: - Split the jolt_vm witness module by stage and polynomial family (spartan_outer, stage2/3/6, registers, ra, ram, trace, streams, provider). - Share require_unique_ids / power_of_two_log_rows helpers across the wrapper and dory_assist providers via protocols/util.rs. - Tighten the core witness data-access API: log_rows-only WitnessDimensions, ViewRequirement-based oracle_view, and removal of dead encodings, policies, and builder indirection. - Document the core witness vocabulary types. - Restore the 1604 workspace build. * fix(jolt-witness): correct next_is_noop boundary and bound stage6 RAM remap Addresses review feedback on #1604: - stage2: next_is_noop used is_none_or (-> true at the final cycle), inverting the boundary relative to the canonical is_some_and used by every other path (jolt-core r1cs/inputs.rs, spartan_outer.rs, trace.rs). It feeds ShouldJump = Jump*(1 - NextIsNoop), so the boundary value was inverted. Switch to is_some_and. - stage6: remapped_ram_address was computed inline, skipping the >= ram_k bound that the shared remapped_ram_address() helper (ram.rs) enforces and that stage2 and every ram.rs path route through. An out-of-range remap would index past the ram_k one-hot domain. Route through the helper, keeping the ram_address binding (still needed for ram_access_nonzero). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Michael Zhu <mchl.zhu.96@gmail.com> Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
1 parent 971ce3e commit 07a8896

35 files changed

Lines changed: 7835 additions & 0 deletions

Cargo.lock

Lines changed: 15 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ members = [
3434
"crates/jolt-sumcheck",
3535
"crates/jolt-openings",
3636
"crates/jolt-verifier",
37+
"crates/jolt-witness",
3738
"crates/jolt-dory",
3839
"crates/jolt-hyperkzg",
3940
"crates/jolt-riscv",
@@ -389,6 +390,7 @@ jolt-crypto = { path = "./crates/jolt-crypto" }
389390
jolt-field = { path = "./crates/jolt-field" }
390391
jolt-openings = { path = "./crates/jolt-openings" }
391392
jolt-verifier = { path = "./crates/jolt-verifier" }
393+
jolt-witness = { path = "./crates/jolt-witness" }
392394
jolt-poly = { path = "./crates/jolt-poly" }
393395
jolt-r1cs = { path = "./crates/jolt-r1cs" }
394396
jolt-transcript = { path = "./crates/jolt-transcript" }

crates/jolt-witness/Cargo.toml

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
[package]
2+
name = "jolt-witness"
3+
version = "0.1.0"
4+
edition = "2021"
5+
license = "MIT OR Apache-2.0"
6+
description = "Witness oracle infrastructure for Jolt proving"
7+
repository = "https://github.com/a16z/jolt"
8+
keywords = ["SNARK", "zkvm", "witness"]
9+
categories = ["cryptography"]
10+
11+
[lints]
12+
workspace = true
13+
14+
[features]
15+
default = []
16+
field-inline = [
17+
"jolt-claims/field-inline",
18+
"jolt-lookup-tables/field-inline",
19+
"jolt-program/field-inline",
20+
"jolt-riscv/field-inline",
21+
]
22+
23+
[dependencies]
24+
jolt-claims.workspace = true
25+
jolt-field.workspace = true
26+
jolt-lookup-tables.workspace = true
27+
jolt-poly.workspace = true
28+
jolt-program.workspace = true
29+
jolt-riscv.workspace = true
30+
rayon.workspace = true
31+
thiserror.workspace = true
32+
33+
[dev-dependencies]
34+
common.workspace = true
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
/// Dimensions of a multilinear witness polynomial.
2+
///
3+
/// The evaluation domain is always a power of two, so only the variable count
4+
/// is stored; the row count is derived.
5+
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
6+
pub struct WitnessDimensions {
7+
pub log_rows: usize,
8+
}
9+
10+
impl WitnessDimensions {
11+
/// Panics if `log_rows >= usize::BITS`; a domain that large is a
12+
/// programming error, not recoverable input.
13+
pub const fn new(log_rows: usize) -> Self {
14+
assert!(
15+
log_rows < usize::BITS as usize,
16+
"log_rows must be smaller than usize::BITS"
17+
);
18+
Self { log_rows }
19+
}
20+
21+
pub const fn rows(&self) -> usize {
22+
1 << self.log_rows
23+
}
24+
}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
/// Physical representation of a polynomial's evaluations in views and stream
2+
/// chunks.
3+
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
4+
pub enum PolynomialEncoding {
5+
/// One field element per row.
6+
#[default]
7+
Dense,
8+
/// Small-scalar values (e.g. `u64` words or signed increments) promoted to
9+
/// field elements on use.
10+
Compact,
11+
/// Rows form a `K x T` grid in which each cycle column has at most one
12+
/// nonzero entry; only the hot index per cycle is stored.
13+
OneHot,
14+
}

crates/jolt-witness/src/error.rs

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
use thiserror::Error;
2+
3+
#[derive(Clone, Debug, Error, PartialEq, Eq)]
4+
pub enum WitnessError {
5+
#[error("unknown witness oracle in namespace `{namespace}`")]
6+
UnknownOracle { namespace: &'static str },
7+
#[error("requested witness view is unavailable in namespace `{namespace}`")]
8+
UnavailableView { namespace: &'static str },
9+
#[error("invalid witness dimensions in namespace `{namespace}`: {reason}")]
10+
InvalidDimensions {
11+
namespace: &'static str,
12+
reason: String,
13+
},
14+
#[error("invalid witness data in namespace `{namespace}`: {reason}")]
15+
InvalidWitnessData {
16+
namespace: &'static str,
17+
reason: String,
18+
},
19+
#[error("witness provider does not support this view: {view}")]
20+
UnsupportedView { view: &'static str },
21+
}

crates/jolt-witness/src/lib.rs

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
//! Witness oracle infrastructure for modular Jolt proving.
2+
//!
3+
//! This crate owns data-access abstractions for witness material, not protocol
4+
//! order or backend allocation policy.
5+
6+
mod dimensions;
7+
mod encoding;
8+
mod error;
9+
mod namespace;
10+
mod opening;
11+
mod polynomial;
12+
mod provider;
13+
mod public;
14+
mod streaming;
15+
16+
pub mod protocols;
17+
18+
pub use dimensions::WitnessDimensions;
19+
pub use encoding::PolynomialEncoding;
20+
pub use error::WitnessError;
21+
pub use namespace::{NamespaceId, OracleKind, OracleRef, WitnessNamespace};
22+
pub use opening::OpeningWitness;
23+
pub use polynomial::{
24+
MaterializationPolicy, OracleDescriptor, PolynomialView, RetentionHint, ViewRequirement,
25+
};
26+
pub use protocols::jolt_vm::{
27+
RaFamilyCycleIndexSource, RaFamilyCycleIndices, RA_FAMILY_MAX_BYTECODE_CHUNKS,
28+
RA_FAMILY_MAX_INSTRUCTION_CHUNKS, RA_FAMILY_MAX_RAM_CHUNKS,
29+
};
30+
pub use provider::{CommittedWitnessProvider, WitnessProvider};
31+
pub use public::PublicValue;
32+
pub use streaming::{
33+
PolynomialBatchChunk, PolynomialBatchStream, PolynomialChunk, PolynomialChunkKind,
34+
PolynomialStream,
35+
};
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
use core::{fmt::Debug, hash::Hash};
2+
3+
/// Label identifying which protocol a witness item belongs to; appears in
4+
/// every [`crate::WitnessError`].
5+
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
6+
pub struct NamespaceId {
7+
pub name: &'static str,
8+
}
9+
10+
impl NamespaceId {
11+
pub const fn new(name: &'static str) -> Self {
12+
Self { name }
13+
}
14+
}
15+
16+
/// Type-level identity of one protocol's witness taxonomy.
17+
///
18+
/// Implemented by uninhabited enums (no values exist; all dispatch is
19+
/// compile-time). The associated types bind the protocol's polynomial,
20+
/// opening, public-input, and challenge identifier spaces, so oracles from
21+
/// different protocols cannot be mixed up.
22+
pub trait WitnessNamespace {
23+
type CommittedId: Copy + Debug + Eq + Hash;
24+
type VirtualId: Copy + Debug + Eq + Hash;
25+
type OpeningId: Copy + Debug + Eq + Hash;
26+
type PublicId: Copy + Debug + Eq + Hash;
27+
type ChallengeId: Copy + Debug + Eq + Hash;
28+
29+
const ID: NamespaceId;
30+
}
31+
32+
/// Committed polynomials go through the commitment scheme; virtual
33+
/// polynomials are derived during proving and never committed.
34+
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
35+
pub enum OracleKind<C, V> {
36+
Committed(C),
37+
Virtual(V),
38+
}
39+
40+
/// Typed reference to a single polynomial within namespace `N`.
41+
#[derive(Debug, PartialEq, Eq, Hash)]
42+
pub struct OracleRef<N: WitnessNamespace> {
43+
pub kind: OracleKind<N::CommittedId, N::VirtualId>,
44+
}
45+
46+
// Manual impls: deriving would incorrectly require `N: Clone + Copy` even
47+
// though `N` only appears through its associated types.
48+
impl<N: WitnessNamespace> Clone for OracleRef<N> {
49+
fn clone(&self) -> Self {
50+
*self
51+
}
52+
}
53+
54+
impl<N: WitnessNamespace> Copy for OracleRef<N> {}
55+
56+
impl<N: WitnessNamespace> OracleRef<N> {
57+
pub const fn committed(id: N::CommittedId) -> Self {
58+
Self {
59+
kind: OracleKind::Committed(id),
60+
}
61+
}
62+
63+
pub const fn virtual_polynomial(id: N::VirtualId) -> Self {
64+
Self {
65+
kind: OracleKind::Virtual(id),
66+
}
67+
}
68+
}

crates/jolt-witness/src/opening.rs

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
use crate::{OracleRef, WitnessNamespace};
2+
3+
/// Claimed evaluation of `oracle` at `point`: the witness-side data backing
4+
/// one opening claim.
5+
#[derive(Clone, Debug, PartialEq, Eq)]
6+
pub struct OpeningWitness<F, N: WitnessNamespace> {
7+
pub oracle: OracleRef<N>,
8+
pub point: Vec<F>,
9+
pub value: F,
10+
}
11+
12+
impl<F, N: WitnessNamespace> OpeningWitness<F, N> {
13+
pub fn new(oracle: OracleRef<N>, point: Vec<F>, value: F) -> Self {
14+
Self {
15+
oracle,
16+
point,
17+
value,
18+
}
19+
}
20+
}

0 commit comments

Comments
 (0)