Skip to content

UniqueVotesWithSameTarget caller contract: cmpVotes must be seat-index-aware #240

Description

@dnadales

Problem

PR #2020 made UniqueVotesWithSameTarget a properly opaque carrier whose construction checks for duplicates, replacing the silent-dedup hazard at the type level (option (a) of the original forgeCert dedup concern).
The remaining concern is at the caller side: uniqueness is parameterized by the cmpVotes :: Vote crypto committee -> Vote crypto committee -> Ordering function the caller supplies, so the duplicate-rejection guarantee is only as strong as that comparator.

For WFALS and EveryoneVotes the underlying hazard is two votes sharing a SeatIndex but differing in signature / VRF output:

  • WFALS.implForgeCert (WFALS.hs:456) calls NEMap.fromAscList voters while signatures are aggregated separately.
    If two voters entries share a SeatIndex, the cert's seat-index map has fewer entries than the signature aggregate, and downstream verifyCert fails with the opaque "number of keys and signatures do not match" error.
  • EveryoneVotes.implForgeCert (EveryoneVotes.hs:265) has the same shape via NESet.fromList voters.

The Peras integration site that builds UniqueVotesWithSameTarget from inbound votes must therefore choose a cmpVotes that returns EQ for any two votes that would collide at the seat-index level (or, more conservatively, on underlying voter identity).

Proposed fix

  • Locate the call site that builds UniqueVotesWithSameTarget for the Peras voting committee.
  • Confirm cmpVotes orders EQ on shared SeatIndex for both persistent and non-persistent variants of WFALS and EveryoneVotes Vote constructors.
  • Add a property test that generates votes with seeded seat-index collisions and asserts ensureUniqueVotesWithSameTarget returns Left (DuplicateVotes …) for them.

References

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type

Projects

No projects

Relationships

None yet

Development

No branches or pull requests

Issue actions