Skip to content

Require distinct input notes - #323

Open
HDauven wants to merge 1 commit into
phoenix/identity-sender-keyfrom
phoenix/distinct-inputs
Open

HDauven wants to merge 1 commit into
phoenix/identity-sender-keyfrom
phoenix/distinct-inputs

Conversation

@HDauven

@HDauven HDauven commented Oct 10, 2026 •

Copy link
Copy Markdown
Member

Stacked on #322.

The transaction circuit now requires the tree positions of its inputs to be pairwise distinct. The check takes two gates per pair (0, 2, 6 and 12 for 1 to 4 inputs) and leaves the public inputs unchanged.

The 2- to 4-input circuits change, so their verifier-data test assets are updated. These are the final ones of the stack. The 1-input circuit and its verifier data are unchanged.

Resolves #315

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🔵 Needs a closer look

The zero-knowledge circuit and verifier-data changes require expert validation and coordinated deployment with downstream verifiers.

1 open finding
What changed in this PR

Enforces distinct transaction inputs by constraining their Merkle-tree positions pairwise.

Changes:

  • Adds inverse-based uniqueness constraints and regression tests for 2–4 inputs.
  • Regenerates affected verifier data while preserving the 1-input circuit.
  • Updates public documentation and changelog.
File Description
circuits/​src/​circuit_impl.rs Implements position uniqueness constraints.
circuits/​src/​lib.rs Documents the new input invariant.
circuits/​tests/​distinct_inputs.rs Tests rejection of duplicate inputs.
circuits/​tests/​verifier_data.rs References regenerated verifier data.
circuits/​README.md Documents input uniqueness.
circuits/​CHANGELOG.md Records the behavior change.
circuits/​tests/​assets/​4e5a…e6b.vd Removes superseded 2-input verifier data.
circuits/​tests/​assets/​3331…997.vd Removes superseded 3-input verifier data.
circuits/​tests/​assets/​a7ff…902.vd Removes superseded 4-input verifier data.
circuits/​tests/​assets/​bc91…a47.vd Adds regenerated 2-input verifier data.
circuits/​tests/​assets/​b19b…df9.vd Adds regenerated 3-input verifier data.
circuits/​tests/​assets/​d3a6…e23.vd Adds regenerated 4-input verifier data.

🧠 Review effort: Balanced


💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread circuits/src/circuit_impl.rs Outdated
@HDauven
HDauven force-pushed the phoenix/distinct-inputs branch from e2d9c7a to fb6a2d5 Compare October 10, 2026 23:13
@HDauven

HDauven commented Oct 10, 2026

Copy link
Copy Markdown
Member Author

Force-pushed: rebased on #322 with the verifier-data assets and gate counts updated, and the comment Copilot flagged reworded.

@HDauven
HDauven force-pushed the phoenix/distinct-inputs branch from fb6a2d5 to 875f374 Compare October 11, 2026 01:32
@HDauven

HDauven commented Oct 11, 2026

Copy link
Copy Markdown
Member Author

Force-pushed: rebased on the amended #322, with the verifier data regenerated.

@HDauven
HDauven marked this pull request as ready for review October 11, 2026 02:02

@moCello moCello left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

APPROVE — The inverse-witness constraint is sound for every pair, it binds the same position witness that the note hash and the nullifier use, and the regression test isolates it. Each copied input keeps a valid opening, signature and nullifier, and every test note holds the same value, so only the new constraint can reject the duplicate.

`TxCircuit` checks each input on its own, so nothing in the circuit
required the inputs to be different notes. The transfer contract rejects
repeated nullifiers.

Constrain the input positions to be pairwise distinct. For every pair,
the prover supplies the inverse of the difference of the two positions,
and `(pos_i - pos_j)·inv = 1` holds only when they differ. The note hash
and the nullifier of each input are both computed from its position
witness, and the Merkle opening proves the note hash to be in the tree.
The check takes two gates per pair, 0, 2, 6 and 12 for 1 to 4 inputs,
and leaves the public inputs unchanged.

The regression proves the honest transaction, then the same transaction
with each input repeated in every later slot, which must be
unsatisfiable. Without the constraint, the regression fails.

The 2- to 4-input circuits change with these gates, and with them their
verifier data, so the test assets are regenerated. The 1-input circuit
has no pair of inputs and keeps its verifier data.
@HDauven
HDauven force-pushed the phoenix/distinct-inputs branch from 875f374 to 92393f0 Compare October 11, 2026 17:43
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.

Require distinct input notes in the transaction circuit

3 participants