Hi @predge-ai, thanks for the tag. Answers from Konclave (shared vaults, FROST over PCZTs, signing in the browser).
1. Would we run it? Yes, if it is data: files plus the expected result, which we wire to our own signer in our own CI. We would keep our own tests too. One thing decides whether the vectors mean anything. A PCZT on its own cannot be “tampered”: a swapped recipient is swapped relative to what was approved. So a case needs the PCZT together with what the signer was told to expect: the approved payment (address, amount, memo), the group key, the signer’s own receivers and the block height. And each refused file should come with its accepted twin, changed in one place, so a signer that refuses everything, or refuses for the wrong reason, does not pass.
2. Cases that worried us most. These come from our own signer’s history. They are in our changelogs (project, app), most with what was open:
- The signature share is made over a signing package whose message is not the sighash the device computed from its own PCZT. A check next to the signing call was not enough for us. It had to be inside it.
- A spend that is not under the vault’s group key.
- What the device shows was read from fields the signature does not cover: an output that does not match its note commitment, an address label that is not the receiver, a memo that differs from the approved one.
- Fee. “Above ZIP 317” needs a height. Under ZIP 2009 the marginal fee is 1,000 zatoshis from mainnet block 3,590,000, so the same file is right or wrong depending on when it is mined.
- Change paid to a receiver that is not in the device’s own record.
- The coordinator asking for a second, different transaction for the same approval.
We do not pass everything ourselves. Our open items are under Known limits in the same file.
3. Adapter. A library call first (Rust, usable from WASM), with a thin stdin/stdout wrapper over it. The first and last cases above are not files, they are a sequence of messages, and a CLI that takes one PCZT cannot express them. I would also give each case an expected refusal class from a short shared list, and let each signer map its own errors to it.
Two notes on the design:
- A new case in a public set tells everyone how to attack each signer that does not pass it yet. “Failures go privately to the maintainer first” covers the results. I would do the same for new cases: maintainers who run the set see a case some days before it is published.
- Each team runs this in its own CI, so a pass is that team’s own report. Useful against regressions, and not an audit.
@Khadim, the tamper cases in your approved work (#490) are the natural start. I would rather contribute to one set than run two. Where would you want shared cases to live? We can write ours up as vectors for whichever home you two agree on, after the milestone we are measuring this month.
To be clear, this is an answer about the design. Whether any of it should be funded is for ZCG, and I am not arguing either way.