Skip to content

feat(transcript): name each challenge's role and width - #33

Draft
quangvdao wants to merge 2 commits into
a16z:mainfrom
quangvdao:explicit-challenge-widths
Draft

quangvdao wants to merge 2 commits into
a16z:mainfrom
quangvdao:explicit-challenge-widths

Conversation

@quangvdao

@quangvdao quangvdao commented Oct 23, 2026 •

Copy link
Copy Markdown
Contributor

Closes #32.

Summary

The Transcript trait becomes positional:

  • append_serde takes no label.
  • challenge_scalar takes a Challenge role instead of a label.
  • Each role states its bad-value count (bad_values()) and how wide a transcript may draw it (width()). β, α and d may be short scalars, with losses 2, 4 and 3. The others are full width.

A transcript can then size short draws from Dory's own soundness facts, rather than inferring them from labels or from draw position. Issue #32 has the reasoning behind the numbers.

Changes

  • src/primitives/transcript.rs:
    • adds Challenge, ChallengeWidth and TranscriptScalar;
    • makes the trait positional;
    • documents the draw order in both modes;
    • drops append_bytes, append_field, append_group and reset from the trait, since Dory never called them.
  • src/evaluation_proof.rs, src/reduce_and_fold.rs: drop labels and pass roles. The draw logic is unchanged.
  • src/backends/arkworks/blake2b_transcript.rs: absorbs each message as a u64 LE length and then its bytes, with no label. Challenges are drawn as before, at full width. new, reset and an unlabeled append_bytes stay as inherent methods. New tests check that the role is not absorbed and that back-to-back draws differ.
  • tests/arkworks/draw_schedule.rs (new): records the prover's and verifier's transcript calls on real proofs, at shapes (nu, sigma) = (1,1), (1,2), (2,2), (2,3) and (3,3), in both modes. It checks that:
    • the two logs are equal, and match the documented schedule, absorb lengths included;
    • in every squeeze run, only the first draw may be short, and that draw's loss is at least the sum of the run's bad_values;
    • the per-role table matches 129, 130 and 130 bits at λ = 128;
    • a transcript that honors Short widths proves and verifies.
  • tests/arkworks/zk.rs: the transcript replay helper is updated.
  • Statement binding (docs only): the transcript module and trait docs, the prove and verify docs, and the README now warn that Dory does not absorb the commitment, the evaluation, the point, or nu/sigma, so callers must absorb them before proving or verifying. The README example now does this on both sides. The ChallengeWidth::Short docs also say that the prover panics on a zero β, α or γ, while the verifier rejects it. Transcript bytes are unchanged.
  • CHANGELOG.md: an "Unreleased" entry.

Compatibility

This is a breaking change, for 0.5.0:

  • Other Transcript implementations need mechanical edits.
  • Blake2bTranscript proofs differ from 0.4.2, because labels are no longer absorbed.

I checked the matching adapter change in Jolt (jolt-dory) against this branch, with Jolt's dory-pcs dependency pointed at it. Its 47 tests pass, and its transcript bytes are identical to those under 0.4.2 for 2 to 6 variables in transparent mode.

Testing

  • cargo fmt --check.
  • cargo clippy --all-targets -D warnings, for features backends,parallel,cache,disk-persistence, the same with zk, and with --no-default-features.
  • cargo doc --all-features -D warnings.
  • cargo nextest run: 90 of 90 pass with the transparent features, and 148 of 148 with zk.
  • All 7 examples run.

Plain cargo test with the cache feature fails, on this branch and on 0.4.2 alike: tests/arkworks/cache.rs fills the global prepared-point cache with random points, and later tests in the same process use them. This is separate from #24, which is about torn setup files. CI uses nextest, so it is unaffected.

The soundness argument for the widths (issue #32) is a paper argument. The tests pin the draw schedule and the widths, not the bound itself. A review of the span table in Challenge::bad_values is the most useful check.

🤖 Generated with Claude Code

The Transcript trait is now positional. append_serde takes no label, and
challenge_scalar takes a Challenge role instead of a label. Each role
states how many challenge values let a false claim through (bad_values)
and how wide a transcript may draw it (width): beta, alpha and d may be
short scalars with losses 2, 4 and 3, the rest full width. Alpha's loss
covers gamma, which shares the last alpha's squeeze run.

A transcript can then size short draws from Dory's own soundness facts
instead of inferring them from labels or from draw position.

The trait drops append_bytes, append_field, append_group and reset, which
Dory never called. Blake2bTranscript absorbs messages unlabeled, so its
proofs change; it still draws every challenge at full width.

tests/arkworks/draw_schedule.rs pins the draw order and the absorbs
between draws in both modes, checks each squeeze run's loss against its
bad values, and proves and verifies with short draws.
Dory absorbs only the prover's messages, not the commitment, the
evaluation, the point, or the nu/sigma split. Say so prominently in the
transcript module and trait docs, in the prove and verify docs, and in the
README, and make the README example absorb the statement on both sides.

Also note that the prover panics on a zero beta, alpha or gamma, beside the
verifier's rejection. No change to transcript bytes.
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.

Name each transcript challenge's role and width instead of passing labels

1 participant