Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
dfd11a6
spec: jolt-core transcript migration to spongefish split-trait surface
shreyas-londhe Jun 3, 2026
9e20487
feat(wip): optimized challenge for poseidon
Vishalkulkarni45 Jun 3, 2026
f9babe9
feat: migrate jolt-core to spongefish NARG (host path)
Vishalkulkarni45 Jun 5, 2026
0f07113
feat: migrate jolt-core to spongefish NARG (zk path)
Vishalkulkarni45 Jun 5, 2026
1c4271d
refactor(jolt-core): drop legacy transcript stack, bind FS instance
Vishalkulkarni45 Jun 6, 2026
b641b41
refactor: retire legacy transcript facade, finish spongefish migration
Vishalkulkarni45 Jun 7, 2026
04ed412
refactor(transcript): simplify uni-skip verify to &self; fix stale Po…
Vishalkulkarni45 Jun 8, 2026
ba1a330
refactor(transcript): use full-field challenges for Poseidon, not 128…
Vishalkulkarni45 Jun 8, 2026
3460813
chore: fix typos, taplo fmt, and unused-dep lint failures
Vishalkulkarni45 Jun 9, 2026
d1897f8
feat(wip): fold ZK sumcheck/uni-skip round data into the NARG
Vishalkulkarni45 Jun 10, 2026
a8f27de
Merge pull request #1 from shreyas-londhe/vk/jolt-core-transcript-mig…
shreyas-londhe Jun 10, 2026
0f463a2
refactor(transcript): dispatch challenge width on sponge type, not fe…
shreyas-londhe Jun 10, 2026
bb583e1
docs(spec): reconcile spec with review decisions; drop dangling refs
shreyas-londhe Jun 10, 2026
b5b22f1
Merge remote-tracking branch 'upstream/main' into pr-1586-review
shreyas-londhe Jun 10, 2026
1b131eb
fix(ci): repair jolt-sumcheck fuzz target, drop retired jolt-transcri…
shreyas-londhe Jun 10, 2026
a5b6b5f
refactor(zkvm): remove duplicate verifier NARG reads and per-stage bo…
Vishalkulkarni45 Jun 10, 2026
adb6675
fix(deps): bump spongefish 0.6.1 -> 0.6.2 for wasm32 verifier portabi…
shreyas-londhe Jun 11, 2026
5feeda2
fix(fuzz): absorb round poly as one slice in valid_prefix_proof, matc…
shreyas-londhe Jun 11, 2026
77675ae
feat: migrate to field-aligned Poseidon transcript
Vishalkulkarni45 Jun 13, 2026
4d2889d
feat: field-aligned Poseidon transcript + NARG transpiler
Vishalkulkarni45 Jun 13, 2026
7b4deda
fix(review): expect-attr lint + arena compaction guard
shreyas-londhe Jun 15, 2026
c3e524a
chore: use shared NARG frame parser in transpiler
Vishalkulkarni45 Jun 24, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion .github/workflows/fuzz-crates.yml
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,6 @@ jobs:
- jolt-field
- jolt-poly
- jolt-sumcheck
- jolt-transcript
name: Fuzz ${{ matrix.crate }}
concurrency:
group: fuzz-crates-${{ github.head_ref || github.ref }}-${{ matrix.crate }}
Expand Down
17 changes: 10 additions & 7 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ Arkworks dependencies use a fork: `a16z/arkworks-algebra` branch `dev/twist-shou
- `field/`: `JoltField` trait and BN254 scalar field implementation
- `subprotocols/`: Sumcheck (batched, streaming, univariate skip), booleanity checks, BlindFold ZK protocol
- `msm/`: Multi-scalar multiplication
- `transcripts/`: Fiat-Shamir transcripts (Blake2b, Keccak)
- `transcript_msgs.rs`: jolt-core's Fiat-Shamir vocabulary over the spongefish NARG (`FsAbsorb`/`FsChallenge`/`ProverFs`/`VerifierFs` from the `jolt-transcript` crate). The old hand-rolled `transcripts/` module was deleted in the spongefish migration.

**tracer** — RISC-V emulator producing execution traces (`Cycle` per instruction)

Expand All @@ -89,9 +89,11 @@ Most core types are generic over three parameters:
```
F: JoltField — scalar field (BN254 Fr)
PCS: CommitmentScheme<Field = F> — polynomial commitment (DoryCommitmentScheme)
ProofTranscript: Transcript — Fiat-Shamir transcript (Blake2bTranscript)
H: DuplexSpongeInterface — spongefish sponge (RV64IMACSponge: Blake2b512 default / Keccak / Poseidon, cfg-selected)
```

Prove/verify take the role-split spongefish surface (`ProverFs<F>` / `VerifierFs<F>` from `transcript_msgs.rs`), not a single `Transcript` trait. The proof carries the sponge as `PhantomData<fn() -> (C, H)>` — a compile-time link so a proof made under sponge `H` can only be verified under `H`.

### Prover Pipeline

1. **Trace**: Execute guest ELF in tracer emulator → `Vec<Cycle>` + `JoltDevice` (I/O)
Expand Down Expand Up @@ -136,16 +138,17 @@ The `zk` Cargo feature (`cfg(feature = "zk")`) controls zero-knowledge mode:
|---|---|---|
| Sumcheck proving | `BatchedSumcheck::prove` — cleartext round polys | `BatchedSumcheck::prove_zk` — Pedersen-committed |
| Uni-skip | `prove_uniskip_round` | `prove_uniskip_round_zk` |
| Proof contains | `Claims<F>` (all opening claims) | `BlindFoldProof` (no cleartext claims) |
| Proof contains | NARG + `Claims<F>` (opening claims, structural) | NARG only — BlindFold written per-field into the NARG (no `BlindFoldProof` field) |
| `input_claim()` | Called, appended to Fiat-Shamir transcript | Skipped; `input_claim_constraint()` used by BlindFold |
| Output claim check | Explicit equality check | Skipped; verified by BlindFold R1CS |
| Opening proof | `bind_opening_inputs` (raw eval) | `bind_opening_inputs_zk` (committed eval) |

**Key cfg-gated items:**
- `JoltProof::opening_claims: Claims<F>` — `#[cfg(not(feature = "zk"))]`
- `JoltProof::blindfold_proof: BlindFoldProof` — `#[cfg(feature = "zk")]`
- Prover uses `#[cfg(feature = "zk")]` / `#[cfg(not(feature = "zk"))]` blocks — compile-time path selection, no runtime `zk_mode` field
- Verifier detects mode from proof at runtime: `proof.stage1_sumcheck_proof.is_zk()` — stored as `VerifierOpeningAccumulator::zk_mode`
- `JoltProof::opening_claims: Claims<F>` — `#[cfg(not(feature = "zk"))]`. **Structural** (a deliberate NARG hard-limit), NOT in the NARG.
- `JoltProof::blindfold_proof` was **removed** under the full-NARG migration: the BlindFold proof is written **per-field into the NARG** (`subprotocols/blindfold/protocol.rs`), not a struct field. The dory `joint_opening_proof` likewise stays structural (the other NARG hard-limit); everything else (commitments, advice presence frame, sumcheck/uni-skip round data, ZK Pedersen commitments) lives in the `JoltProof::narg` byte-string, sealed by `check_eof` + the MAL-1 outer-envelope guard.
- `JoltProof::zk_mode: bool` — a **runtime** mode flag that replaced the per-stage `SumcheckInstanceProof::{Clear,Zk}` / `UniSkipFirstRoundProofVariant` markers and `verify_zk_consistency` (both removed). The prover sets it from `cfg!(feature = "zk")`; the verifier selects which NARG read-frames to expect off `proof.zk_mode`.
- Prover uses `#[cfg(feature = "zk")]` / `#[cfg(not(feature = "zk"))]` blocks for compile-time path selection; the proof additionally carries the runtime `zk_mode` bool so the (compile-time-mode-agnostic) verifier can dispatch.
- Verifier detects mode at runtime via `proof.zk_mode` — stored as `VerifierOpeningAccumulator::zk_mode`.

**CRITICAL — Verifier `new_from_verifier` must support both modes:**

Expand Down
32 changes: 25 additions & 7 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -110,8 +110,8 @@ members = [
"examples/sig-recovery/host",
"examples/sig-recovery/guest",
"zklean-extractor",
"z3-verifier",
"transpiler",
"z3-verifier",
"jolt-eval",
"jolt-eval/macros",
"jolt-eval/guest-sandbox",
Expand Down Expand Up @@ -259,7 +259,7 @@ blake2 = "0.11.0-rc.6"
blake3 = { version = "1.8.5" }
light-poseidon = "0.4"
digest = "0.11"
spongefish = { version = "0.6.1", default-features = false, features = [
spongefish = { version = "0.6.2", default-features = false, features = [
"sha3",
] }
jolt-optimizations = { git = "https://github.com/a16z/arkworks-algebra", branch = "dev/twist-shout" }
Expand Down
1 change: 1 addition & 0 deletions crates/jolt-blindfold/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ description = "Generic BlindFold verifier infrastructure for the Jolt zkVM"
workspace = true

[dependencies]
ark-serialize.workspace = true
jolt-claims.workspace = true
jolt-crypto.workspace = true
jolt-field.workspace = true
Expand Down
21 changes: 14 additions & 7 deletions crates/jolt-blindfold/src/protocol.rs
Original file line number Diff line number Diff line change
Expand Up @@ -611,14 +611,15 @@ mod tests {
use crate::{
BlindFoldStage, BlindFoldStatement, CommittedClaimRows, FinalOpeningBinding, OpeningAlias,
};
use ark_serialize::CanonicalSerialize;
use jolt_claims::{constant, opening, Expr};
use jolt_crypto::{Bn254, Bn254G1, JoltGroup, Pedersen, PedersenSetup, VectorCommitment};
use jolt_field::{Fr, FromPrimitiveInt};
use jolt_sumcheck::{
CommittedOutputClaims, CommittedRound, CommittedSumcheckProof, SumcheckDomainSpec,
SumcheckError, SumcheckStatement,
};
use jolt_transcript::{AppendToTranscript, Blake2bTranscript, Transcript};
use jolt_transcript::{prover_transcript, Blake2b512};

#[derive(Clone, Debug)]
struct TestStage {
Expand Down Expand Up @@ -696,7 +697,7 @@ mod tests {
final_openings: Vec<FinalOpeningBinding<Fr, usize, Com>>,
) -> Result<BlindFoldStatement<Fr, usize, Com>, VerificationError<Fr>>
where
Com: Clone + AppendToTranscript,
Com: Clone + CanonicalSerialize,
{
if stages.len() != proofs.len() {
return Err(VerificationError::StageCountMismatch {
Expand All @@ -705,7 +706,7 @@ mod tests {
});
}

let mut transcript = Blake2bTranscript::<Fr>::new(b"blindfold");
let mut transcript = prover_transcript(b"blindfold", [0u8; 32], Blake2b512::default());
let mut next_opening_id = 0usize;
let stages = stages
.iter()
Expand Down Expand Up @@ -744,7 +745,7 @@ mod tests {
final_openings: Vec<FinalOpeningBinding<Fr, usize, Com>>,
) -> BlindFoldProtocol<Fr, Com>
where
Com: Clone + AppendToTranscript,
Com: Clone + CanonicalSerialize,
{
let statement = try_statement_from_proofs(stages, proofs, final_openings)
.expect("statement builds from committed proofs");
Expand Down Expand Up @@ -910,7 +911,8 @@ mod tests {

let statement = SumcheckStatement::new(1, 1);
let proof = proof(&[(11, 1)], &[21]);
let mut transcript = Blake2bTranscript::<Fr>::new(b"blindfold-alias");
let mut transcript =
prover_transcript(b"blindfold-alias", [0u8; 32], Blake2b512::default());
let consistency = proof
.verify_committed_consistency(statement, &mut transcript)
.expect("committed proof is consistent");
Expand Down Expand Up @@ -942,7 +944,8 @@ mod tests {

let statement = SumcheckStatement::new(1, 1);
let proof = proof(&[(11, 1)], &[21]);
let mut transcript = Blake2bTranscript::<Fr>::new(b"blindfold-alias");
let mut transcript =
prover_transcript(b"blindfold-alias", [0u8; 32], Blake2b512::default());
let consistency = proof
.verify_committed_consistency(statement, &mut transcript)
.expect("committed proof is consistent");
Expand Down Expand Up @@ -1047,7 +1050,11 @@ mod tests {
fn rejects_extra_output_claim_rows_without_typed_openings() {
let statement = SumcheckStatement::new(1, 1);
let proof = proof(&[(11, 1)], &[21, 22]);
let mut transcript = Blake2bTranscript::<Fr>::new(b"blindfold-output-row-count");
let mut transcript = prover_transcript(
b"blindfold-output-row-count",
[0u8; 32],
Blake2b512::default(),
);
let consistency = proof
.verify_committed_consistency(statement, &mut transcript)
.expect("committed proof is consistent");
Expand Down
Loading