Skip to content

Counting interface for the indifferentiability arc - #27

Merged
daira merged 14 commits into
mainfrom
indiff-counting
Aug 20, 2026
Merged

daira merged 14 commits into
mainfrom
indiff-counting

Conversation

@daira

@daira daira commented Aug 13, 2026

Copy link
Copy Markdown
Owner

The counting side of the indifferentiability arc (#25; the game side is zcash/ironwood#198): everything the ironwood-side sampler and single-query lemma consume, with no probability in this repo.

Hashing/FibreBound.lean — the fibre bound

Away from the input u = 0, every point of the target curve has at most 10 preimages under SSWUParams.map, over any field where -1 is a square (both Pasta base fields, q ≡ 1 (mod 4)). Nonzero inputs are never exceptional there — ta = 0 would exhibit the nonsquare Z as -1 times a square — so a preimage of an abscissa is a root of the explicit product polynomial Φ_x combining the two branch equations cleared of their common denominator: nonzero of degree at most 10, because its second factor has degree exactly 6 with leading coefficient -B·Z³. The input u = 0 is excluded from the count; a consumer needing the unconditional bound adds it back as at most one extra preimage per point, which is how the ironwood sampler instantiates its fibre-size hypothesis at 11. The optimal constant is 4 (oddness pairs ±u across P and -P, and each branch equation is a quadratic in t), recorded in the module doc as a follow-up; the sampler only needs some explicit constant.

The deployed maps, per curve

isSquare_neg_one by Euler's criterion, the generic composition step card_fibre_comp_le (composing with an injective map does not grow fibres), and Pallas/Vesta.card_mapToCurve_fibre_le through iso_map_bijective. The census records both endpoints, whose native leaves are the Tonelli–Shanks validity witnesses and, through the isogeny's bijectivity, the order witnesses.

Hashing/TwoTermUniformity.lean — deviation exports and the transport

sum_abs_prob_dev_le states the L¹ probability deviation unsquared, against any budget whose square dominates the squared bound, so the ℝ≥0∞-side consumer never needs a square root and a concrete budget is checked by squaring, in exact arithmetic. card_dev_ge_le is the Chebyshev-style counting form of the L² bound: regularity does not lower-bound individual fibres, so the rejection sampler's acceptance constant holds only outside a bad set of fibres, whose size this bounds. sum_abs_pairCount_sub_le bounds the zero-repair transport: mappings agreeing away from a single input have two-term pair counts within 4·#F - 2 of each other in L¹. sum_abs_prob_dev_transport_le combines the two: a mapping agreeing away from a single input with a Weil-bounded one has regularity distance at most ε + (4·#F − 2)/(#F)² — the composed form the ironwood side consumes at the deployed mapToCurve.

The absorbed ironwood extras

Two commits adopt the content of zcash/ironwood's Zcash/Circuits/Specs/CompEllipticExtras.lean, closing #12. CurveForms/ShortWeierstrass.lean gains the rfl projection lemmas SWPoint.add_x/SWPoint.add_y, y_eq_pm_of_onCurve_x_eq (two points on the curve sharing an x-coordinate have y-coordinates equal up to sign), SWPoint.onCurve_of_ne_zero, and SWPoint.eq_pm_of_x_eq (nonzero representable points sharing an x-coordinate are equal up to sign) — ironwood's y_eq_or_y_eq_neg_of_onCurve and eq_or_eq_neg_of_x_eq, renamed to name the shared-abscissa premiss. The last subsumes the private copy that Isogenies/Homomorphism.lean carried. Its ≠ 0 premisses are necessary at SWCurve generality: only B ≠ 0 is bundled, so a curve whose B is a square has a genuine point (0, √B) sharing x = 0 with the 𝒪 sentinel.

Fields/Pasta.lean gains the Fp/Fq abbreviations under their pasta_curves letters, reversing the "not to move" note in #12. The Pallas-side twins neg_five_not_isCube/no_onCurve_y_zero that #12 also requested were already added by #19. ironwood drops its copies of all of this when it bumps its pin.

The Weil constant: calculated, and proven on paper

Hashing/WellDistributed.lean now records that the WeilBounded constant for the deployed Z = -13 mappings has been calculated — |S_f(χ)| ≤ 10·√q + 1 on both iso-curves, from genus-6 branch coverings, recorded as C = 21/2 — by zcash/pasta's weilbound.sage. The calculation is proven on paper in design/weil-constant-derivation.md — modulo results cited as established mathematics: Weil's theorem in the form of FFSTV's Lemma 1 and Theorem 3, and standard hyperelliptic point bookkeeping — with a Background section pointing to material on the relevant algebraic geometry. The symbolic identities it relies on are checked by scripts/weil-derivation-checks.sage. What remains of #28 is formalizing the calculation in Lean; Weil's theorem itself stays a cited input.

Per the parallel-iteration plan, this merges once the ironwood side compiles against it. It now does (zcash/ironwood branch fv/indiff-sampler), consuming the L¹ exports through the transport and the fibre bound through the rejection-sampling simulator's deployed instantiation; card_dev_ge_le remains for the planned estimate of the capped simulator's average bias.

🤖 Claude Opus 4.8, Claude Fable 5

Base automatically changed from hashing-style to main August 13, 2026 15:38
@daira daira linked an issue Aug 13, 2026 that may be closed by this pull request
@daira
daira marked this pull request as ready for review August 13, 2026 19:05
daira added a commit to daira/ironwood that referenced this pull request Aug 15, 2026
Bump the CompElliptic pin from fd997734 to 23ac3369, the head of the
indiff-counting branch (daira/CompElliptic#27, the milestone-1 counting
interface for the hash-to-curve indifferentiability arc), pinned temporarily
until that PR merges. The new revision also carries the Pallas-side twins
neg_five_not_isCube / no_onCurve_y_zero and the content of
Zcash/Circuits/Specs/CompEllipticExtras.lean (daira/CompElliptic#12), so
ironwood's copies are dropped:

- Delete CompEllipticExtras.lean. Its importers now import the CompElliptic
  modules they use directly, as do MulFixed/Theorems.lean and
  MulFixed/ShortTheorems.lean, which had been reaching CompElliptic through
  transitive imports.
- Delete the Pallas-side twins from Specs/Pallas.lean; CompElliptic proves
  them verbatim, by the same kernel-tier proofs, so the census is unchanged.
- Rename uses of y_eq_or_y_eq_neg_of_onCurve to its upstream name
  y_eq_pm_of_onCurve_x_eq, and prove Point.y_eq_or_neg_of_same_x through it
  instead of repeating the square-difference argument.
- Drop the module from the book's source map.

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
daira added a commit to daira/ironwood that referenced this pull request Aug 15, 2026
Bump the CompElliptic pin from fd997734 to 23ac3369, the head of the
indiff-counting branch (daira/CompElliptic#27, the milestone-1 counting
interface for the hash-to-curve indifferentiability arc), pinned temporarily
until that PR merges. The new revision also carries the Pallas-side twins
neg_five_not_isCube / no_onCurve_y_zero and the content of
Zcash/Circuits/Specs/CompEllipticExtras.lean (daira/CompElliptic#12), so
ironwood's copies are dropped:

- Delete CompEllipticExtras.lean. Its importers now import the CompElliptic
  modules they use directly, as do MulFixed/Theorems.lean and
  MulFixed/ShortTheorems.lean, which had been reaching CompElliptic through
  transitive imports.
- Delete the Pallas-side twins from Specs/Pallas.lean; CompElliptic proves
  them verbatim, by the same kernel-tier proofs, so the census is unchanged.
- Rename uses of y_eq_or_y_eq_neg_of_onCurve to its upstream name
  y_eq_pm_of_onCurve_x_eq, and prove Point.y_eq_or_neg_of_same_x through it
  instead of repeating the square-difference argument.
- Drop the module from the book's source map.

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
daira and others added 7 commits August 16, 2026 01:30
…oCurve

`mapHashOutputsToCurve` and its `_eq` lemma took the field-to-curve map as
`m`. Ironwood's group-hash development calls that map `f` (`f : F → G`), so
rename the parameter to `f` for cross-repo consistency. Callers are
unaffected — the map is passed positionally.

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
… 10 elements

The counting fact the indifferentiability arc's rejection sampler consumes
(zcash/ironwood#198, CompElliptic#25). On a field where -1 is a square
(both Pasta base fields), a nonzero input is never exceptional, so a
nonzero preimage of an abscissa x is a root of the explicit product
polynomial combining the two branch equations cleared of their common
denominator: nonzero of degree at most 10, since its second factor has
degree exactly 6 with leading coefficient -B·Z³. The input u = 0 is
excluded rather than counted: the probability analysis prices pairs
containing 0 in its existing zero-repair correction. The optimal constant
is 4, recorded in the module doc as a planned follow-up.

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
-1 is a square in both Pasta base fields (q ≡ 1 mod 4, Euler's criterion),
so the generic SSWU fibre bound applies, and the isogeny is injective on
rational points (iso_map_bijective), so it carries through the composition:
at most 10 nonzero preimages per point under the deployed mapToCurve. The
generic composition step is card_fibre_comp_le in FibreBound. The census
records both endpoints; they consume the Tonelli-Shanks validity witnesses
and, through the isogeny's bijectivity, the order witnesses.

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
The counting interface the indifferentiability game side consumes
(zcash/ironwood#198, CompElliptic#25), in three statements.
sum_abs_prob_dev_le is the L¹ probability deviation unsquared, stated
against any budget whose square dominates the squared bound, so the
consumer never needs a square root and a concrete budget is checked by
squaring in exact arithmetic. card_dev_ge_le is the Chebyshev-style
counting form of the L² bound: regularity does not lower-bound individual
fibres, so the rejection sampler's acceptance constant holds only outside
a bad set of fibres, whose size this bounds. sum_abs_pairCount_sub_le
prices replacing the zero-repaired mapping by the deployed one: mappings
agreeing away from one input have two-term pair counts within 4·#F - 2 in
L¹, by splitting every pair count at the pairs containing that input.

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
…Extras

zcash/ironwood carried Zcash/Circuits/Specs/CompEllipticExtras.lean, written
in CompElliptic's own namespaces as explicit upstreaming candidates. Adopt
the curve lemmas into CurveForms/ShortWeierstrass.lean:

- SWPoint.add_x / SWPoint.add_y: rfl projection lemmas for the coordinates
  of a sum.
- y_eq_pm_of_onCurve_x_eq (was y_eq_or_y_eq_neg_of_onCurve; the rename names
  the shared-abscissa premiss): two points on the curve sharing an
  x-coordinate have y-coordinates equal up to sign.
- SWPoint.onCurve_of_ne_zero: a nonzero representable point is on the curve.
- SWPoint.eq_pm_of_x_eq (was SWPoint.eq_or_eq_neg_of_x_eq): nonzero
  representable points sharing an x-coordinate are equal up to sign. This
  subsumes the private eq_or_eq_neg_of_x_eq in Isogenies/Homomorphism.lean,
  which is removed. The ≠ 0 premisses are necessary at SWCurve generality:
  SWCurve requires only B ≠ 0, so a curve whose B is a square has a genuine
  point (0, √B) sharing x = 0 with the 𝒪 sentinel without being equal to it
  up to sign.

Closes #12.

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
Consumers refer to the Pallas base and scalar fields by their pasta_curves
letters, Fp and Fq. Host the abbreviations beside the role-named fields they
alias. This reverses the "not to move" assessment of #12:
the letters are pasta_curves' own convention, not Zcash-specific usage.

Fields/Pasta.lean is generated, so the abbreviations are emitted by
scripts/gen_pasta.py and the file regenerated from it (CI checks the
reproduction).

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…apping

sum_abs_prob_dev_transport_le combines sum_abs_prob_dev_le with
sum_abs_pairCount_sub_le: a mapping agreeing away from a single input with
a Weil-bounded one has regularity distance at most ε + (4·#F − 2)/(#F)².
This is the form the ironwood-side single-query bias consumes at the
deployed mapToCurve, whose zero-repaired variant carries the Weil-bound
hypothesis.

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>

@daira daira left a comment

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Self-reACK

daira added a commit to daira/ironwood that referenced this pull request Aug 16, 2026
Bump the CompElliptic pin from fd997734 to a18340e, the head of the
indiff-counting branch (daira/CompElliptic#27, the milestone-1 counting
interface for the hash-to-curve indifferentiability arc), pinned temporarily
until that PR merges. The new revision also carries the Pallas-side twins
neg_five_not_isCube / no_onCurve_y_zero and the content of
Zcash/Circuits/Specs/CompEllipticExtras.lean (daira/CompElliptic#12), so
ironwood's copies are dropped:

- Delete CompEllipticExtras.lean. Its importers now import the CompElliptic
  modules they use directly, as do MulFixed/Theorems.lean and
  MulFixed/ShortTheorems.lean, which had been reaching CompElliptic through
  transitive imports.
- Delete the Pallas-side twins from Specs/Pallas.lean; CompElliptic proves
  them verbatim, by the same kernel-tier proofs, so the census is unchanged.
- Rename uses of y_eq_or_y_eq_neg_of_onCurve to its upstream name
  y_eq_pm_of_onCurve_x_eq, and prove Point.y_eq_or_neg_of_same_x through it
  instead of repeating the square-difference argument.
- Drop the module from the book's source map.

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
daira and others added 2 commits August 16, 2026 17:27
FFSTV's C = 52 was quoted as the constant expected for the deployed
mappings. Their Theorem 6 in fact treats a sibling encoding: Z = -1, over
fields of size ≡ 3 (mod 4), with a quadratic-residue sign rule. The
deployed variant differs in all three parameters. RFC 9380 excludes
Z = -1, and its search gives Z = -13 for each iso-curve independently.
The Pasta base fields are ≡ 1 (mod 4). The sign rule is the parity-based
sgn0, which is not a multiplicative character, so the indicator step of
FFSTV's proof does not apply as written.

Reword the deployed-size estimates as order-of-magnitude expectations,
and record the differences in WellDistributed's References note —
including that the sign-convention-free reduction should make a redone
bound independent of the sign rule.

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
The fibre-bound module doc described a sampler design that was
superseded: the sampler does not ride the zero-repair transport; its
deployed instantiation counts the input 0 directly, as at most one
extra preimage per point. Say that, and drop the transport claim.

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
daira added a commit to daira/ironwood that referenced this pull request Aug 16, 2026
Bump the CompElliptic pin from fd997734 to a18340e, the head of the
indiff-counting branch (daira/CompElliptic#27, the milestone-1 counting
interface for the hash-to-curve indifferentiability arc), pinned temporarily
until that PR merges. The new revision also carries the Pallas-side twins
neg_five_not_isCube / no_onCurve_y_zero and the content of
Zcash/Circuits/Specs/CompEllipticExtras.lean (daira/CompElliptic#12), so
ironwood's copies are dropped:

- Delete CompEllipticExtras.lean. Its importers now import the CompElliptic
  modules they use directly, as do MulFixed/Theorems.lean and
  MulFixed/ShortTheorems.lean, which had been reaching CompElliptic through
  transitive imports.
- Delete the Pallas-side twins from Specs/Pallas.lean; CompElliptic proves
  them verbatim, by the same kernel-tier proofs, so the census is unchanged.
- Rename uses of y_eq_or_y_eq_neg_of_onCurve to its upstream name
  y_eq_pm_of_onCurve_x_eq, and prove Point.y_eq_or_neg_of_same_x through it
  instead of repeating the square-difference argument.
- Drop the module from the book's source map.

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
daira and others added 2 commits August 17, 2026 12:13
zcash/pasta's weilbound.sage calculates the character-sum bound for the
deployed Z = -13 mappings on both iso-curves: the branch coverings have
genus 6 (re-rooted as hyperelliptic models over the input line), the
monodromy is dihedral, the exceptional input set is exactly {0} for
fields of size = 1 (mod 4), and the bound comes out at 10*sqrt(q) + 3,
with C = 21/2 recorded. Update the module doc's covering-genus mentions
(previously FFSTV's 8) and replace "remains to be carried out" with the
calculated state, keeping the calculation/proof distinction explicit:
the derivation write-up that would make C = 21/2 citable is tracked at
issue #28.

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
The hand derivation behind zcash/pasta's weilbound.sage, for issue #28.
The two branch covers re-root as hyperelliptic models sharing one
degree-12 core polynomial, making them quadratic twists by Z of a
single genus-6 curve. Eisenstein total ramification over A*x + B = 0
discharges the no-unramified-subcover hypothesis unconditionally.
Oddness gives a sign-free assembly with exact boundary bookkeeping
(using that #E' is odd and that exactly one twist is rational over
each of u = 0 and infinity), sharpening the bound to
|S_f(chi)| <= 10*sqrt(q) + 1 on both iso-curves.

A Background section explains the algebraic-geometry concepts for an
audience of cryptographic engineers, with full-text references where
available.

The symbolic identity checks the document relies on are committed as
scripts/weil-derivation-checks.sage, and WellDistributed.lean now cites
the write-up and the sharper additive term.

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
daira added a commit to daira/ironwood that referenced this pull request Aug 17, 2026
Bump the CompElliptic pin from fd997734 to a18340e, the head of the
indiff-counting branch (daira/CompElliptic#27, the milestone-1 counting
interface for the hash-to-curve indifferentiability arc), pinned temporarily
until that PR merges. The new revision also carries the Pallas-side twins
neg_five_not_isCube / no_onCurve_y_zero and the content of
Zcash/Circuits/Specs/CompEllipticExtras.lean (daira/CompElliptic#12), so
ironwood's copies are dropped:

- Delete CompEllipticExtras.lean. Its importers now import the CompElliptic
  modules they use directly, as do MulFixed/Theorems.lean and
  MulFixed/ShortTheorems.lean, which had been reaching CompElliptic through
  transitive imports.
- Delete the Pallas-side twins from Specs/Pallas.lean; CompElliptic proves
  them verbatim, by the same kernel-tier proofs, so the census is unchanged.
- Rename uses of y_eq_or_y_eq_neg_of_onCurve to its upstream name
  y_eq_pm_of_onCurve_x_eq, and prove Point.y_eq_or_neg_of_same_x through it
  instead of repeating the square-difference argument.
- Drop the module from the book's source map.

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
daira and others added 3 commits August 17, 2026 21:33
…sistent

We map from the iso-curve *across* to the main curve, not *down* to it.
(FWIW, for me the iso-curve has always been on the left and the main
curve on the right.) The "across" wording is used in `ThreeIsogeny.lean`
and in `zcash/ironwood`.

Signed-off-by: Daira-Emma Hopwood <daira@jacaranda.org>
Close the two remaining gaps in the derivation, upgrading it to a
proof modulo cited results (Weil via FFSTV Lemma 1 and Theorem 3, and
standard hyperelliptic point bookkeeping):

- Genus: Φ is squarefree unconditionally. Φ = φ(ta) for a cubic φ
  with disc(φ) = −A⁶·B²·(4·A³ + 27·B²), so a repeated root of Φ needs
  either a repeated root of φ or a critical point of ta on a root of
  φ; both reduce to A·B ≠ 0 and the ellipticity of E′.
- Boundary bookkeeping: the fibre correspondence and the four extra
  points are derived on the smooth model W² = H_j(u) via the explicit
  substitution W = y·s_j(u), instead of asserted. The −A·B-square
  variant is stated correctly: the extra points then map to the two
  rational points over w = 0 and the additive constant is 3, not 1;
  the deployed instances are in the nonsquare case.

The checks script gains the corresponding identities (φ composition,
discriminant, and critical values; model substitutions; boundary
values, leading coefficients, and images), replaces the models check
with the s_j form (one of the old pair was inert: `assert … or
True`), and moves its comments to Unicode math.

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
Update the WellDistributed module doc from calculated-only status: the
bound is now proven in design/weil-constant-derivation.md, modulo the
results it cites as established mathematics, and what remains of #28
is the Lean formalization.

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
@daira
daira merged commit 824bf13 into main Aug 20, 2026
8 checks passed
@daira
daira deleted the indiff-counting branch August 20, 2026 05:41
daira added a commit to daira/ironwood that referenced this pull request Aug 20, 2026
Bump the CompElliptic pin from fd997734 to a18340e, the head of the
indiff-counting branch (daira/CompElliptic#27, the milestone-1 counting
interface for the hash-to-curve indifferentiability arc), pinned temporarily
until that PR merges. The new revision also carries the Pallas-side twins
neg_five_not_isCube / no_onCurve_y_zero and the content of
Zcash/Circuits/Specs/CompEllipticExtras.lean (daira/CompElliptic#12), so
ironwood's copies are dropped:

- Delete CompEllipticExtras.lean. Its importers now import the CompElliptic
  modules they use directly, as do MulFixed/Theorems.lean and
  MulFixed/ShortTheorems.lean, which had been reaching CompElliptic through
  transitive imports.
- Delete the Pallas-side twins from Specs/Pallas.lean; CompElliptic proves
  them verbatim, by the same kernel-tier proofs, so the census is unchanged.
- Rename uses of y_eq_or_y_eq_neg_of_onCurve to its upstream name
  y_eq_pm_of_onCurve_x_eq, and prove Point.y_eq_or_neg_of_same_x through it
  instead of repeating the square-difference argument.
- Drop the module from the book's source map.

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

@dannywillems dannywillems left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Post-ACK - good to have it here!

rw [div_mul_div_comm, show u*u = u^2 from (pow_two u).symm]
exact (eq_div_iff (pow_ne_zero 2 hu)).mpr (hZu.trans hs)

/-- **At most 10 nonzero preimages per abscissa.** On a field where `-1` is

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Post-ACK note: this is interesting by the way. It is not anywhere in the RFC if I paid attention enough.

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.

Upstream ironwood's CompEllipticExtras lemmas and the Pallas curve twins

2 participants