Skip to content

Add spongefish-dsfs: Duplex-Sponge Fiat-Shamir compiler#153

Closed
ricardo-perello wants to merge 10 commits into
arkworks-rs:mainfrom
ricardo-perello:refactor/codec-back-to-spongefish
Closed

Add spongefish-dsfs: Duplex-Sponge Fiat-Shamir compiler#153
ricardo-perello wants to merge 10 commits into
arkworks-rs:mainfrom
ricardo-perello:refactor/codec-back-to-spongefish

Conversation

@ricardo-perello

Copy link
Copy Markdown
Collaborator

Summary

Adds a new sibling crate spongefish-dsfs implementing the Duplex-Sponge Fiat-Shamir (DSFS) transformation of [Chiesa–Orrù 2025], Construction 4.3. The compiler takes a public-coin interactive argument or reduction and produces a non-interactive proof using spongefish's existing duplex sponge transcript machinery.

DSFS is the transformation that makes spongefish useful end-to-end: a typed protocol → a transcript → a byte string the verifier checks. Today spongefish stops at the transcript; this PR adds the missing top layer.

What's new

spongefish-dsfs (new workspace crate)

The compiler:

use spongefish_dsfs::{Dsfs, Keccak};

let nia = Dsfs::<_, _>::new(my_protocol, Keccak::default());
let proof = nia.prove(&session, &instance, &witness);
nia.verify(&session, &instance, &proof)?;

Public surface:

  • Dsfs<IA, S, H = Keccak, const SALT_LEN: usize = 0> — wraps an InteractiveArgument, implements NonInteractiveArgument. Const-generic salt length, explicit sponge parameter.
  • DsfsReduction<IR, S, H, SALT_LEN> — symmetric for InteractiveReduction (verifiers output a reduced target instance instead of accept/reject).
  • SpongeProver / SpongeVerifier — adapters that view spongefish::ProverState / VerifierState as a typed prover/verifier channel.
  • TranscriptSponge — initialization trait. Keccak uses domsep.to_prover(); StdHash (SHAKE128) uses domsep.std_prover() so DSFS output is byte-compatible with spongefish's existing standard-hash transcript path (and σ-proofs Nizk).
  • NargSecurity + security_for_concrete_instance / security_for_instance_bound and reduction variants — applies the bounds of [CO25], Theorems 6.1, 6.2, 7.1 to derive concrete NARG soundness / knowledge-soundness / zero-knowledge errors from the IA's per-round metadata plus the sponge's (alphabet_size, capacity, rate, delta) parameters.

Transcript invariants the compiler maintains:

  • public inputs (protocol id, sponge info, session, instance) absorbed before the first challenge;
  • every prover message absorbed before the next verifier challenge;
  • deterministic verifier replay;
  • EOF check on verification — trailing proof bytes are rejected.

Companion crate: ia-core

The DSFS compiler needs a vocabulary for "what's an interactive argument" and "what's a non-interactive argument". That vocabulary lives in a small ia-core crate that spongefish-dsfs depends on:

trait InteractiveArgument {
    type Instance;
    type Witness;
    fn protocol_id(&self) -> impl AsRef<[u8]>;
    fn prove<P: ProverChannel>(&self, ch: &mut P, ...);
    fn verify<V: VerifierChannel>(&self, ch: &mut V, ...) -> VerificationResult<()>;
}

trait NonInteractiveArgument {
    type Session;  type Instance;  type Witness;  type Proof;
    fn protocol_id(&self) -> impl AsRef<[u8]>;
    fn prove(&self, ...) -> Self::Proof;
    fn verify(&self, ...) -> VerificationResult<()>;
}

Plus analogous InteractiveReduction / NonInteractiveReduction for reduction-style protocols, the channel traits ProverChannel / VerifierChannel, and a security-metadata module. ia-core itself is pure-no_std, has no transcript / sponge knowledge, and re-exports spongefish's codec traits (Encoding, Decoding, NargSerialize, NargDeserialize, Deserialize) for protocol authors.

Hosted at https://github.com/ricardo-perello/argus (path dep here; will be published when the IA/IR API stabilizes).

Workspace plumbing

  • New spongefish-dsfs workspace member; standard version.workspace = true / lints inheritance.
  • [patch.crates-io] spongefish = { path = "spongefish" } so transitive deps (ia-core resolved through spongefish-dsfs) see the local copy instead of the registry version during development.

What's not in this PR

  • No changes to spongefish core. Transcript layer, DomainSeparator, sponge instantiations (Keccak, StdHash, all of instantiations::*), and codec traits (Encoding, Decoding, NargSerialize, NargDeserialize) are exactly where they were. spongefish-dsfs consumes them through their existing public API.
  • No changes to existing examples / tests in spongefish. examples/schnorr.rs, examples/bulletproof.rs, the bench harness, the drivers' Unit impls, the derive_generics tests — all untouched.
  • No new transcript / sponge primitives. DSFS is built on the existing duplex sponge construction. Adding SHA-512-padded protocol-id derivation, instance binding, etc., is what DomainSeparator::derive already does upstream.

Verification

cargo build --workspace --all-features
cargo test  --workspace --all-features    # 100% pass
cargo build -p spongefish --no-default-features
cargo build -p spongefish-dsfs --no-default-features
cargo doc   --workspace --no-deps --all-features

cargo tree -p spongefish | grep ia-core is empty — spongefish core has no upward dependency. The arrows are strictly:

spongefish core             ── no dep on ia-core or spongefish-dsfs
ia-core                     ──▶ spongefish core (for codec traits)
spongefish-dsfs             ──▶ spongefish core
                            ──▶ ia-core

Reference

  • [CO25] Chiesa, Orrù. "Building Cryptographic Proofs from Hash Functions: Fiat–Shamir." eprint 2025/536, §4 (Construction 4.3).
  • IETF draft: draft-irtf-cfrg-fiat-shamir.

Follow-ups (separate PRs)

  • σ-proofs Nizk byte-compat fixtures land in the consumer (Argus) — not needed here.
  • Once ia-core is published to crates.io, drop the path dep in favor of a versioned one.

Optional tweaks you might want:

Move DSFS compiler implementation under spongefish::dsfs and re-export Argus-owned codec traits through spongefish for compatibility with existing derive outputs and paths.
Make p3-* features enable ia-core's p3 codecs and keep only the local Unit impls to avoid orphan impls.
Address clippy warnings and minor API polish in the new spongefish::dsfs module and related code.
…urn to spongefish

Splits the April 2026 codec inversion into three cleanly-stacked crates:

- spongefish: transcript + codecs (Encoding/Decoding/NargSerialize/NargDeserialize/
  Deserialize) + foreign-type drivers. No ia-core dependency.
- ia-core (Argus): IA/IR/NIA/NIR protocol abstractions, depends on spongefish for
  codec traits.
- spongefish-dsfs: DSFS bridge crate (Dsfs/DsfsReduction wrappers + free fns) that
  depends on both spongefish and ia-core.

This reverses the prior arrangement where spongefish had a backwards dep on ia-core
just to see the codec traits. Codec impls for ark_ff/ark_ec/bls12_381/curve25519-
dalek/p256/k256/p3 fields are merged into spongefish/src/drivers/<type>.rs alongside
the existing Unit impls. SmallFp codec impls are not yet ported (ia-core did not
have them).

[patch.crates-io] spongefish = { path = "spongefish" } added to the spongefish
workspace so transitive deps (ia-core) see the local copy instead of the stale
crates.io 0.7.0 publish.

The free-fn DSFS surface (prove/verify/*_with_*) stays pub for now; it will be
flipped to pub(crate) in a follow-up after Argus call sites are swept onto the
Dsfs::new(...) wrapper.

cargo test --workspace --all-features passes.
The `Dsfs::new(...).prove(...)` / `DsfsReduction::new(...).prove(...)` wrappers
are now the only public DSFS surface. Internal helper free fns kept (called by
the wrapper):

- `prove_with_sponge_and_salt`
- `verify_with_sponge_and_salt`
- `prove_reduction_with_sponge_and_salt_full` (private)
- `verify_reduction_with_sponge_and_salt`

Deleted (13 fns, no public callers and not needed internally since the wrapper
parametrizes `Dsfs<IA, S, H, SALT_LEN>` over sponge + salt-length):

- `prove`, `prove_with_salt`, `prove_with_sponge`
- `verify`, `verify_with_salt`, `verify_with_sponge`
- `prove_reduction`, `prove_reduction_with_salt`, `prove_reduction_with_sponge`,
  `prove_reduction_with_sponge_and_salt`
- `verify_reduction`, `verify_reduction_with_salt`, `verify_reduction_with_sponge`

The `Dsfs::new` const-generic salt + explicit sponge field already cover every
variant the deleted free fns expressed. Custom-salt example:
`Dsfs::<_, _, _, 16>::new(ia, sponge)`. Custom-sponge example:
`Dsfs::<_, _, StdHash, 0>::new(ia, StdHash::default())`.

Argus workspace tests pass (except 3 pre-existing sigma-bridge golden_vectors).
The ia-core → spongefish → ia-core → spongefish round trip left cosmetic
reformatting (doc-comment rewrites, import reordering, comment deletions) in
files that are otherwise upstream's own and functionally unchanged. Reverted
to `upstream/main` exact content:

- spongefish/src/{codecs,io,error}.rs
- spongefish/src/drivers/{ark_ec_impl,ark_ff_impl,bls12_381_impl,
  curve25519_dalek_impl,p256_impl,secp256k1_impl,p3_baby_bear,p3_koala_bear,
  p3_mersenne31,tests}.rs

Also reverted spongefish/src/domain_separator.rs to PR arkworks-rs#114's exact version
(dropped a stray blank line, two `#[allow(dead_code)]`, and a `const fn
instance` tweak that don't belong in this PR — that file is PR arkworks-rs#114's).

Net result: this PR's spongefish/ diff vs upstream is now only:
- spongefish/src/deserialize.rs — new channel-side `Deserialize` shim
- ~5 lines of spongefish/src/lib.rs (declare/export `deserialize`, drop the
  moved-out `pub mod dsfs`)
- domain_separator.rs / narg_prover.rs / narg_verifier.rs / tests.rs /
  lib.rs-macro — byte-identical to PR arkworks-rs#114 (arkworks-rs#153 stacks on arkworks-rs#114; this part
  of the diff disappears once arkworks-rs#114 merges to main)

cargo test --workspace --all-features still passes.
@ricardo-perello

Copy link
Copy Markdown
Collaborator Author

⚠️ This PR stacks on #114

spongefish-dsfs uses DomainSeparator::derive(protocol_id, sponge_info, session), which is introduced by #114 (mandatory-session domain separator). This PR is branched on top of #114's branch, so until #114 merges into main, the diff here also shows #114's changes to:

  • spongefish/src/domain_separator.rs
  • spongefish/src/narg_prover.rs, spongefish/src/narg_verifier.rs (doc-test macro syntax)
  • spongefish/src/tests.rs
  • the domain_separator! macro in spongefish/src/lib.rs

Those files are byte-identical to #114 — not changes owned by this PR. Once #114 lands, rebasing this branch on main collapses the diff to just the genuinely new surface:

  • the new spongefish-dsfs crate
  • spongefish/src/deserialize.rs (channel-side Deserialize shim)
  • ~5 lines in spongefish/src/lib.rs (declare/export deserialize)

Suggested review order: review/merge #114 first, then this. Reviewing the spongefish-dsfs/ crate itself is independent and can happen any time.

@mmaker

mmaker commented Jun 2, 2026

Copy link
Copy Markdown
Member

sorry, but this is an insanely large PR with a description that is AI generated, jargon that is internal to argus/ai core, new dependencies without justification.

This library is meant to be used externally, this is maybe a good PoC but doesn't meet the bar of the rest of the project.

@mmaker mmaker closed this Jun 2, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants