The last question is whether \(\Fsig \) is the strongest object of its shape. It is not, and the gap is not an oversight: it is what sanitization costs.
A further finalization: collision resistance
\(\id .\opdef {FinColl}()\) from \(\id '\) (collision resistance)
It takes the search reading, winning being meant to be hard rather than no better than a guess.
Proposition 21.4 (\(\psig \) has it, \(\Fsig \) does not). \(\psig \) has \(\opl {FinColl}\) within \(q \cdot \varepsilon _{\op {col}}(\mathcal {B}_{\op {col}})\) for an adversary \(\mathcal {B}_{\op {col}}\) against \(\DS \) built as in Proposition 21.1. The functionality \(\Fsig \) does not have it within any \(\varepsilon < 1\): there are \(\Zenv ^{*}\) and an occupant \(\mathcal {X}^{*}\) with \(\Pr [\Win _{\op {FinColl}}] = 1\).
Proof. For \(\psig \): a winning trace exhibits one \(\sigma \) verifying under an honest party’s \(\vk \) on two distinct messages, and verification is \(\DS .\op {Ver}\) by line 10, so the pair is a collision for \(\DS \) under a key drawn on uniform coins. The adversary \(\mathcal {B}_{\op {col}}\) plants its challenge key at a guessed one of the at most \(q\) generating parties, answers that party’s signing from its oracle and runs the rest itself, and outputs the two messages and the signature.
For \(\Fsig \): let \(\mathcal {X}^{*}\) answer every \(\op {Gen}\) query with a fresh key, every \(\op {Verify}\) query with \(0\), and both \(\op {Sign}\) queries with one fixed \(\sigma ^{*} \in \Sigs \). Let \(\Zenv ^{*}\) corrupt nobody, call \(\op {Gen}()\) then \(\op {Sign}(\msg )\) and \(\op {Sign}(\msg ')\) for \(\msg \neq \msg '\) at an honest party, then \(\op {Verify}\) on both triples, then finalize. The first signature is accepted, \(\Clean _{\sigma }\) asking only that \(\sigma ^{*}\) be a signature and that \(\V {Ver}[\vk ,\msg ,\sigma ^{*}] \neq 0\), which holds, it being unset; \(\V {Ver}[\vk ,\msg , \sigma ^{*}] \gets 1\). The second is accepted for the same reason at the other message, \(\V {Ver}[\vk ,\msg ',\sigma ^{*}]\) being unset as well, and \(\V {Ver}[\vk ,\msg ',\sigma ^{*}] \gets 1\). Both verifications then return the recorded \(1\), and the verdict at line 4 gives \(1\) with certainty. □
The attack is not a defect to be patched — or rather, it can be patched, by adding to \(\Clean _{\sigma }\) the conjunct that \(\sigma \) be recorded valid for no other message under \(\vk \), and the interest is in what that would cost. Sanitization exists so that a functionality’s guarantees do not depend on the slot answering helpfully (Chapter 12); each conjunct of a \(\Clean \) predicate is a guarantee bought, and each is also a value the simulator may no longer choose. The functionality \(\Fsig \) as written buys correctness and unforgeability and declines to buy collision resistance, which is a defensible reading of what a signature functionality is for — and the consequence, made precise by Proposition 21.4, is that a realization may be strictly stronger than the ideal object it realizes.
That is worth sitting with, because it inverts the usual intuition. An ideal functionality is often read as the best possible behaviour, with realizations approximating it from below; here \(\psig \) satisfies a property \(\Fsig \) provably fails, and no amount of emulation transfers it downward — Corollary 5.11 carries properties from the ideal object to the realization, never the other way. What an ideal functionality fixes is what a protocol may be relied on for, not what it happens to achieve; anything a realization achieves beyond that is real, and is invisible to every argument that goes through the ideal object.