Skip to content
Draft
Show file tree
Hide file tree
Changes from 68 commits
Commits
Show all changes
71 commits
Select commit Hold shift + click to select a range
d7e46e7
bump to gr1cs interface
z-tech Mar 20, 2026
6b753e5
chkpt
z-tech Mar 25, 2026
6f836e1
clippy
z-tech Mar 25, 2026
e4920ef
fix upstream crypto primitives
z-tech Mar 25, 2026
a66f122
comm complexity reduction inner product sumcheck api
z-tech Apr 8, 2026
7706766
chkpt
z-tech Apr 8, 2026
dabc150
rm rev pinning sumcheck
z-tech Apr 8, 2026
312e220
more opts
z-tech Apr 9, 2026
5bf6753
Plan 0: phase modules + Oracle abstraction + tracing scaffold
z-tech Apr 18, 2026
2a5379b
Plan O: structured observability — op counters, cpu_ns, JSON layer
z-tech Apr 18, 2026
dfbab4a
Plan B v1: iai-callgrind bench harness + Mac-Docker wrapper
z-tech Apr 18, 2026
9fb6fe1
Plan P: soundness-driven parameter selection
z-tech Apr 18, 2026
695eac9
Plan T v1: negative-path verifier tests + Fiat-Shamir audit
z-tech Apr 18, 2026
e6452ec
Cleanup after Plans 0 / O / B / P / T
z-tech Apr 18, 2026
8b6e66a
CHANGELOG: document sumcheck communication-reduction work
z-tech Apr 18, 2026
28ab180
gitignore: widen from .claude/settings.local.json to .claude/
z-tech Apr 18, 2026
f36d258
integrate new effsc
z-tech Apr 19, 2026
02b7e13
fix conflicts
z-tech Apr 19, 2026
0c00fcc
Apply suggestion from @winderica
z-tech Apr 28, 2026
375da83
bump effsc w/ spongefish 0.7.0
z-tech May 2, 2026
1427dd2
Merge pull request #24 from compsec-epfl/z-tech/fresh-effsc
z-tech May 2, 2026
36473d5
Merge origin/main into z-tech/general-cleanup
z-tech May 3, 2026
d135f8d
merge
z-tech May 3, 2026
72a8ee4
phases
z-tech May 3, 2026
d2a3893
more ior trait
z-tech May 3, 2026
391c8e8
integrate ark-vc
z-tech May 4, 2026
7aca289
ark-vc HashRegions
z-tech May 4, 2026
e120627
ci: load ark-vc deploy key + rewrite HTTPS to SSH
z-tech May 4, 2026
166c29c
christian comments
z-tech May 5, 2026
0df5adf
remove dyn + fix slides
z-tech May 5, 2026
48ee03f
refactor: tighten prove() input handling, perf, and key types
z-tech May 7, 2026
abe7fad
api: typed AccumulatorEntry + extend() helper
z-tech May 7, 2026
cc0d356
perf: parallelize R1CS::evaluate_bundled with rayon
z-tech May 7, 2026
dc8e4ce
refactor: BatchingStatement::from_phase_outputs as single source of t…
z-tech May 7, 2026
22d3b51
api: hide PhantomData fields and add HashChainWitness::new
z-tech May 7, 2026
0bcd765
serialize: drop assert-len-1 panics, replace wrappers with direct impls
z-tech May 7, 2026
247c551
soundness: implement R1CS::description so index() actually binds matr…
z-tech May 7, 2026
0c51b61
api: add prelude module + drop unused error variants
z-tech May 7, 2026
84b1599
docs: real README with quick-start example
z-tech May 7, 2026
ef5d7e6
perf: fuse (f+ω·p)·t into direct accumulation in twin_constraint
z-tech May 7, 2026
94b4919
sketch: typed IOR composition module (design space, not yet wired)
z-tech May 7, 2026
81734de
sketch: Pipeline trait above IOR, with WARP composition example
z-tech May 7, 2026
1701617
ior: GAT-ify Witness/ProverInputs/VerifierInputs
z-tech May 7, 2026
90dac4a
composition: PesatTwinConstraint pipeline + demo test
z-tech May 7, 2026
c77b288
api: drop BoolResult trait, use stdlib then_some(()).ok_or(...)
z-tech May 7, 2026
7c1536c
composition: extend pipeline to 3 phases (add Ood + TC->Ood glue)
z-tech May 7, 2026
421b485
composition: extend pipeline to 4 phases (add Batching + Ood->Batchin…
z-tech May 7, 2026
fe3d5fd
composition: extend pipeline to 5 phases (add Proximity)
z-tech May 7, 2026
399357b
composition: replace WARP::prove body with WarpPipeline.prove()
z-tech May 7, 2026
53a9238
composition: generic Then<A, B> combinator over Pipeline
z-tech May 7, 2026
b27c688
composition: add WarpPipeline.verify() method
z-tech May 7, 2026
3526f70
composition: replace WARP::verify body with WarpPipeline.verify()
z-tech May 7, 2026
0f04911
composition: restore protocol map in WARP::prove / WARP::verify
z-tech May 8, 2026
1e4edcd
choreography: IOR-uniform protocol map with destructured outputs
z-tech May 12, 2026
b2b4700
ior: collapse 9-type IOR trait to (Input, Output) per side; IOR is th…
z-tech May 12, 2026
8b1f49f
Revert "ior: collapse 9-type IOR trait to (Input, Output) per side; I…
z-tech May 12, 2026
22ae199
ior: restore formal trait + add prove_ior!/verify_ior! macros
z-tech May 12, 2026
366a01d
cleanup: drop dead types, prune verbose comments, drop "phase" vocab
z-tech May 12, 2026
fc1b41d
refactor: directory layout teaches "WARP = choreography of IORs"
z-tech May 12, 2026
98b154d
cleanup
z-tech May 12, 2026
6f3e4b6
Merge remote-tracking branch 'origin/main' into z-tech/ior-with-ark-vc
z-tech May 12, 2026
8494fed
trim: -630 lines via bloat review
z-tech May 12, 2026
d25bbc0
more cleanup
z-tech May 12, 2026
779f868
fmt
z-tech May 12, 2026
bd8886e
more cleanup
z-tech May 12, 2026
b20e761
further cleanup
z-tech May 12, 2026
7814cd7
fmt
z-tech May 12, 2026
f497bb2
warp through vc
z-tech May 13, 2026
9d40a97
chkpt
z-tech May 13, 2026
cf81504
ark-iop
z-tech May 14, 2026
4db2bd3
fix CI
z-tech May 14, 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
2 changes: 2 additions & 0 deletions .cargo/config.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
[net]
git-fetch-with-cli = true
24 changes: 24 additions & 0 deletions .github/workflows/rust.yml
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,14 @@ jobs:
steps:
- uses: actions/checkout@v3

- name: Load ark-vc deploy key
uses: webfactory/ssh-agent@v0.9.0
with:
ssh-private-key: ${{ secrets.ARK_VC_DEPLOY_KEY }}

- name: Rewrite ark-vc HTTPS URL to SSH
run: git config --global url."ssh://git@github.com/arkworks-rs/ark-vc.git".insteadOf "https://github.com/arkworks-rs/ark-vc.git"

- name: Install stable toolchain with clippy
uses: actions-rs/toolchain@v1
with:
Expand All @@ -47,6 +55,14 @@ jobs:
steps:
- uses: actions/checkout@v3

- name: Load ark-vc deploy key
uses: webfactory/ssh-agent@v0.9.0
with:
ssh-private-key: ${{ secrets.ARK_VC_DEPLOY_KEY }}

- name: Rewrite ark-vc HTTPS URL to SSH
run: git config --global url."ssh://git@github.com/arkworks-rs/ark-vc.git".insteadOf "https://github.com/arkworks-rs/ark-vc.git"

- name: Run tests
run: cargo test --verbose

Expand All @@ -55,5 +71,13 @@ jobs:
steps:
- uses: actions/checkout@v3

- name: Load ark-vc deploy key
uses: webfactory/ssh-agent@v0.9.0
with:
ssh-private-key: ${{ secrets.ARK_VC_DEPLOY_KEY }}

- name: Rewrite ark-vc HTTPS URL to SSH
run: git config --global url."ssh://git@github.com/arkworks-rs/ark-vc.git".insteadOf "https://github.com/arkworks-rs/ark-vc.git"

- name: Run tests
run: cargo test --verbose --no-default-features
8 changes: 8 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,14 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).
- **Consolidated error types.** Reduced from 6 error enums to 4. Folded `WARPSumcheckProverError` into `ProverError`, inlined `WARPSumcheckVerifierError` into `VerifierError`, dropped `WARP` prefix. Moved errors from `utils/errs.rs` to `error.rs`.
- **Made `chunk_size` compile-time.** Replaced runtime serialization with a `const fn` computed from `PrimeField::MODULUS_BIT_SIZE`.

### Optimized

- **Reduced inner product sumcheck communication by 1/3.** Updated to `efficient-sumcheck` 2-coefficient round messages: prover sends `(a, b)` instead of `(s(0), s(1), s(1/2))`. Verifier derives the third coefficient as `c = claim - 2a - b`. Updated verifier transcript to read `[F; 2]` instead of `[F; 3]` per round.
- **Adopted `RoundPolyEvaluator` trait for twin constraint sumcheck.** Replaced closure-based `twin_constraint_round_poly` with `TwinConstraintEvaluator` struct implementing the new `RoundPolyEvaluator` trait from `efficient-sumcheck`. The library now handles pair iteration, parallel summation, and SIMD-accelerated reduce.
- **Reduced twin constraint sumcheck communication.** Prover now sends `d` coefficients per round instead of `d+1`; verifier derives the leading coefficient from the sumcheck constraint. Updated `derive_randomness` to read `1 + max(log_n+1, log_m+2)` instead of `2 + max(log_n+1, log_m+2)`.
- **Twin constraint sumcheck 64% faster.** Combined effect of `RoundPolyEvaluator` refactor, library-side optimizations (zero-allocation `poly_ops`, optimized `protogalaxy::fold`), and SIMD-accelerated pairwise reduce. End-to-end prover time improved ~23%.
- **Pinned `ark-ff`/`ark-poly`/`ark-serialize` to rev `285dac2`.** Resolves spongefish BigInt mismatch with upstream `ark-ff` HEAD.

### Fixed

- **BLS test desync.** Fixed `WARPConfig` in the BLS test from `l=4` to `l=8`, matching `l2=4` accumulated instances. The prover absorbed all accumulators unconditionally while the verifier only read `l2` of them, causing a sponge state mismatch.
Expand Down
9 changes: 9 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,19 @@ ark-relations = "0.6.0"
ark-serialize = "0.6.0"
ark-std = "0.6.0"
blake3 = "1.5.0"
rayon = "1"
serde = { version = "1.0.0", features = ["derive"] }
serde_json = "1.0"
spongefish = { version = "0.7.0", features = ["ark-ff"] }
rand_core = { version = "0.6", default-features = false }
effsc = { git = "https://github.com/compsec-epfl/efficient-sumcheck.git" }
thiserror = "2.0.16"
tracing = { version = "0.1", default-features = false, features = ["std", "attributes"] }
tracing-subscriber = { version = "0.3", default-features = false, features = ["fmt", "env-filter", "registry"], optional = true }
libc = { version = "0.2", optional = true }
ark-codes = { git = "https://github.com/z-tech/ark-codes.git", branch = "z-tech/arkworks-0.6.0" }
ark-vc = { git = "https://github.com/arkworks-rs/ark-vc.git", branch = "z-tech/hash-regions" }
ark-mt = { git = "https://github.com/arkworks-rs/ark-vc.git", branch = "z-tech/hash-regions", features = ["blake3", "blake3-field", "vc"] }

[dev-dependencies]
ark-bls12-381 = "0.6.0"
Expand All @@ -36,6 +43,8 @@ default = ["asm"]

asm = ["ark-ff/asm"]

profile = ["dep:tracing-subscriber", "dep:libc"]

[[bench]]
name = "warp_rs"
harness = false
90 changes: 89 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,93 @@
🌀 WARP 🌀

Implementation repo for [WARP](https://eprint.iacr.org/2025/753).
Implementation repo for [WARP](https://eprint.iacr.org/2025/753) — an
accumulation scheme with code-based commitments.

## Status

Ongoing research.

## Quick start

```rust
use warp::{WARPConfig, AccumulatorInstance, AccumulatorWitness, WARPProverKey, WARP};
use warp::utils::poseidon;
use warp::relations::{r1cs::{R1CS, hashchain::HashChainRelation}, BundledPESAT, ToPolySystem};
use ark_codes::{reed_solomon::{ReedSolomon, config::ReedSolomonConfig}, traits::LinearCode};
use ark_crypto_primitives::crh::poseidon::{CRH, constraints::CRHGadget};
use ark_mt::blake3::Blake3FieldHasher;
use ark_bls12_381::Fr as F;

// 1. Build the relation (here: a hash chain of length 10).
let poseidon = poseidon::initialize_poseidon_config::<F>();
let r1cs = HashChainRelation::<F, CRH<_>, CRHGadget<_>>::into_r1cs(&(poseidon, 10))?;

// 2. Pick a code and a hasher.
let code = ReedSolomon::new(ReedSolomonConfig::<F>::default(r1cs.k, r1cs.k.next_power_of_two()));
let hasher = Blake3FieldHasher::<F>::new();

// 3. Configure WARP and instantiate.
// `l1` = fresh-instance batch size, `l` = total accumulator capacity, `s`/`t` = OOD/shift queries.
let cfg = WARPConfig::new(/*l1*/ 4, /*l*/ 4, /*s*/ 8, /*t*/ 7, r1cs.config(), code.code_len());
let warp = WARP::new(cfg, code, r1cs.clone(), hasher);

// 4. Fold a stream of fresh (instance, witness) batches into the accumulator.
let mut acc_x = AccumulatorInstance::empty();
let mut acc_w = AccumulatorWitness::empty();
let pk = WARPProverKey { index: r1cs.clone(), m: r1cs.m, n: r1cs.n, k: r1cs.k };
for batch in batches {
let mut prover_state = /* spongefish prover state */;
let ((new_x, new_w), _proof) = warp.prove(
pk.clone(), &mut prover_state, batch.witnesses, batch.instances,
AccumulatorInstance::empty(), AccumulatorWitness::empty(),
)?;
acc_x = acc_x.extend(new_x);
acc_w = acc_w.extend(new_w);
}

// 5. Final decide (the only non-succinct step — wrap in a SNARK if you need succinctness).
warp.decide(acc_w, acc_x)?;
```

## Picking `(s, t)` for a target security level

The `warp-params` binary picks and validates soundness parameters per
`docs/paper-mods/mod4_parameter_selection.tex`:

```sh
# Pick (s, t) for λ bits of security at a given code rate and field size.
cargo run --release --bin warp-params -- select \
--lambda 128 --rate 1/2 --field-bits 64 --regime conjectured

# Check that a specific (s, t) actually hits λ bits.
cargo run --release --bin warp-params -- validate \
--s 8 --t 128 --lambda 128 --rate 1/2 --field-bits 64 --regime conjectured

# Dump the attested presets as TSV.
cargo run --release --bin warp-params -- table
```

`--regime` picks between `provable` and `conjectured` proximity bounds.
Exit codes: 0 ok, 1 derivation failed / target not met, 2 bad args.

## Layout

- `src/warp/` — `WARP::{prove, verify, decide}` choreography over IORs
- `src/protocol/ior.rs` — the `IOR` trait
- `src/protocol/iors/` — concrete IORs (`pesat`, `twin_constraint`, `bridge`, `ood`, `sample_queries`, `batching`, `proximity`)
- `src/protocol/oracles/` — oracle vocabulary used by IORs
- `src/protocol/transcript/` — transcript absorb / parse helpers
- `src/relations/` — `R1CS`, `BundledPESAT`, `HashChainRelation`
- `src/params/` — soundness-driven `(s, t)` selection backing `warp-params`
- `src/bin/warp-params.rs` — CLI front-end for `src/params/`
- `src/crypto/`, `src/utils/` — Merkle wrapper, field / poly helpers
- `src/profile/` — opt-in tracing layer (gated behind the `profile` feature)
- `tests/integration_warp.rs` — end-to-end on BLS12-381 and Goldilocks
- `tests/verifier_negative.rs` — single-tamper rejection tests

## Running tests / benches

```sh
cargo test --release
cargo bench
```
11 changes: 3 additions & 8 deletions benches/utils/hash_chain.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
use std::marker::PhantomData;

use ark_crypto_primitives::{
crh::poseidon::{constraints::CRHGadget, CRH},
sponge::{poseidon::PoseidonConfig, Absorb},
Expand All @@ -11,15 +9,15 @@ use warp::relations::{
hashchain::{compute_hash_chain, HashChainInstance, HashChainRelation, HashChainWitness},
R1CS,
},
Relation, ToPolySystem,
Arithmetize, Relation,
};

// utilities for the hashchain benchmark
pub fn get_hashchain_r1cs<F: PrimeField + Absorb>(
poseidon_config: &PoseidonConfig<F>,
hashchain_size: usize,
) -> R1CS<F> {
HashChainRelation::<F, CRH<_>, CRHGadget<_>>::into_r1cs(&(
HashChainRelation::<F, CRH<_>, CRHGadget<_>>::arithmetize(&(
poseidon_config.clone(),
hashchain_size,
))
Expand All @@ -37,10 +35,7 @@ pub fn get_hashchain_instance_witness_pairs<F: PrimeField + Absorb>(
let instance = HashChainInstance {
digest: compute_hash_chain::<F, CRH<_>>(poseidon_config, &preimage, hashchain_size),
};
let witness = HashChainWitness {
preimage,
_crhs_scheme: PhantomData::<CRH<F>>,
};
let witness = HashChainWitness::<F, CRH<F>>::new(preimage);
let relation = HashChainRelation::<F, CRH<_>, CRHGadget<_>>::new(
instance,
witness,
Expand Down
97 changes: 28 additions & 69 deletions benches/warp_rs.rs
Original file line number Diff line number Diff line change
@@ -1,98 +1,52 @@
use ark_bls12_381::Fr as BLS12_381;
use ark_codes::reed_solomon::config::ReedSolomonConfig;
use ark_codes::reed_solomon::ReedSolomon;
use ark_codes::traits::LinearCode;

use ark_mt::{
blake3::Blake3FieldHasher, hash_region::HashRegion, scheme::MerkleCommitment,
shape::PerfectBinary,
};
use ark_std::rand::thread_rng;
use ark_vc::mvc::MultiVectorCommitment;
use criterion::{criterion_group, criterion_main, BenchmarkId, Criterion};
use utils::domainsep::init_prover_state;
use utils::hash_chain::{get_hashchain_instance_witness_pairs, get_hashchain_r1cs};
use warp::config::WARPConfig;
use warp::crypto::merkle::blake3::Blake3MerkleTreeParams;
use warp::traits::AccumulationScheme;
use warp::warp::WARPProverKey;
use warp::WARP;

mod utils;
use utils::poseidon;
use warp::relations::BundledPESAT;
use warp::relations::PolyPredicate;
use warp::utils::fields::Goldilocks;

const HASHCHAIN_SIZE: usize = 800;

pub fn bench_rs_warp(c: &mut Criterion) {
let mut rng = thread_rng();
let poseidon_config = poseidon::initialize_poseidon_config::<BLS12_381>();
let r1cs = get_hashchain_r1cs(&poseidon_config, HASHCHAIN_SIZE);

let code_config = ReedSolomonConfig::<BLS12_381>::default(r1cs.k, r1cs.k.next_power_of_two());
let code = ReedSolomon::new(code_config.clone());
let s = 8;
let t = 7;

for l in [32, 64, 128, 256, 512] {
let warp_config = WARPConfig::new(l, l, s, t, r1cs.config(), code.code_len());

let hash_chain_warp = WARP::<_, _, _, Blake3MerkleTreeParams<_>>::new(
warp_config.clone(),
code.clone(),
r1cs.clone(),
(),
(),
);

let instances_witnesses =
get_hashchain_instance_witness_pairs(l, &poseidon_config, HASHCHAIN_SIZE, &mut rng);

let mut group = c.benchmark_group("warp_rs_bls12_381_hash_chain");
group.sample_size(10);
group.bench_with_input(
BenchmarkId::from_parameter(l),
&instances_witnesses,
|b, instance_witnesses| {
b.iter_with_setup(
|| {
let prover_state = init_prover_state();
(prover_state, instance_witnesses.clone())
},
|(mut prover_state, _x_w)| {
let _ = hash_chain_warp
.prove(
(r1cs.clone(), r1cs.m, r1cs.n, r1cs.k),
&mut prover_state,
instances_witnesses.1.clone(),
instances_witnesses.0.clone(),
(vec![], vec![], vec![], (vec![], vec![]), vec![]),
(vec![], vec![], vec![]),
)
.unwrap();
},
);
},
);
}
}

pub fn bench_rs_warp_fields(c: &mut Criterion) {
pub type F = Goldilocks;
let mut rng = thread_rng();
let poseidon_config = poseidon::initialize_poseidon_config::<F>();
let r1cs = get_hashchain_r1cs(&poseidon_config, HASHCHAIN_SIZE);

let code_config = ReedSolomonConfig::<F>::default(r1cs.k, r1cs.k.next_power_of_two());
let code_config = ReedSolomonConfig::<F>::default(
r1cs.k_num_witness_vars,
r1cs.k_num_witness_vars.next_power_of_two(),
);
let code = ReedSolomon::new(code_config.clone());
let s = 2;
let t = 125;

type V = MerkleCommitment<HashRegion<Blake3FieldHasher<F>>, PerfectBinary>;

for l in [32, 64, 128, 256, 512] {
let warp_config = WARPConfig::new(l, l, s, t, r1cs.config(), code.code_len());
let warp_config = WARPConfig::new(l, 0, s, t, r1cs.config(), code.code_len());

let hash_chain_warp = WARP::<_, _, _, Blake3MerkleTreeParams<_>>::new(
warp_config.clone(),
code.clone(),
r1cs.clone(),
(),
(),
);
let pp = <V as MultiVectorCommitment>::setup_multiple(0, code.code_len(), t, &mut rng)
.expect("setup_multiple");
let (ck, vk) = <V as MultiVectorCommitment>::trim_multiple(&pp, 0, code.code_len(), t)
.expect("trim_multiple");
let hash_chain_warp =
WARP::<_, _, _, V>::new(warp_config.clone(), code.clone(), r1cs.clone(), ck, vk);

let instances_witnesses =
get_hashchain_instance_witness_pairs(l, &poseidon_config, HASHCHAIN_SIZE, &mut rng);
Expand All @@ -111,12 +65,17 @@ pub fn bench_rs_warp_fields(c: &mut Criterion) {
|(mut prover_state, _x_w)| {
let _ = hash_chain_warp
.prove(
(r1cs.clone(), r1cs.m, r1cs.n, r1cs.k),
WARPProverKey {
index: r1cs.clone(),
m_num_constraints: r1cs.m_num_constraints,
n_num_variables: r1cs.n_num_variables,
k_num_witness_vars: r1cs.k_num_witness_vars,
},
&mut prover_state,
instances_witnesses.1.clone(),
instances_witnesses.0.clone(),
(vec![], vec![], vec![], (vec![], vec![]), vec![]),
(vec![], vec![], vec![]),
warp::warp::AccumulatorInstance::empty(),
warp::warp::AccumulatorWitness::empty(),
)
.unwrap();
},
Expand Down
Loading
Loading