mldsa: add ML-DSA-87 verify vectors for omitted NTT reduction#255
Conversation
These MlDsaVerify vectors target a verifier that omits a required modular reduction in the verification NTT path, where the inverse-NTT butterfly overflows a 32-bit accumulator. Each vector's verdict diverges between a conforming verifier and an omitting one: forgeries (result=invalid) are wrongly accepted, and valid signatures (result=valid) are wrongly rejected. All vectors share a single ML-DSA-87 public key. Responsible disclosure was fully completed prior to submission: the issue was reported to the affected implementation's maintainers and the fix has already been released. These vectors are published only to guard against the same omission recurring in current or future verifiers. Authors: Sunwoo Lee (@programsurf), Hyuk Lim (@lubroai), Seunghyun Yoon (@yoonsh) Korea Institute of Energy Technology (KENTECH)
|
Thank you again for the research and for submitting test vectors! I tried these and they seem to all fail the I was already investigating, so I took the liberty to fix that, using a degenerate I used Claude to help with the investigation and bruteforce, so I might have missed something. In case let me know! If you're curious, I had the agent upload its notes and programs to https://github.com/filippo-claude/wycheproof-mldsa-reduction-omission, but I have not reviewed them. The new vectors catch the bug in the old WolfSSL with Is it correct that this is the only missing required reduction that can be reached with a KAT, and that it's only possible to generate such a KAT for ML-DSA-87? |
|
Thanks — and thanks especially for the replacement vectors and for opening the PR. We tracked down why ours passed on our side but failed for you, and it turned out to be a message-binding mismatch on our end, not the reduction issue. We had generated and checked the vectors through wolfSSL's no-context verification path, whose message binding differs from FIPS-204 "pure" ML-DSA — the convention the pq-crystals reference and Wycheproof use for an empty context. Once we accounted for that, the discrepancy fully explained itself, and it is orthogonal to the missing-reduction behavior. We confirmed this against the unmodified pq-crystals reference. On your two questions:
Thanks again for the careful review. |
|
Pushed two small commits to get CI green: the fold reused tcId 1–2 (colliding with the existing test group), so I renumbered them to 240–241 and fixed the JSON formatting. All four checks pass now — ready to merge whenever you are. |
Co-authored-by: Hyuk Lim <90449417+lubroai@users.noreply.github.com> Co-authored-by: Seunghyun Yoon <7575205+yoonsh@users.noreply.github.com>
cpu
left a comment
There was a problem hiding this comment.
@FiloSottile Did you want to do another pass?
I think we should squash merge it (vs rebase merge) when ready.
|
Thanks @cpu! When you squash-merge, could you keep all three of us credited as squash commit trailers? |
Yup! Absolutely. I vote we keep the initial message + the trailers and just fold the intermediate commits together so it lands as one discrete commit. |
Thanks for catching this! |
Summary
Adds a new
MlDsaVerifytest vector file,testvectors_v1/mldsa_87_reduction_omission_verify_test.json, that targets verifiers omitting a required modular reduction in the ML-DSA verification NTT path. No schema change — it uses the existingmldsa_verify_schema.json.What these vectors test
When a verifier omits the reduction in the verification NTT path, the inverse-NTT butterfly overflows a signed 32-bit accumulator and the verdict flips. Each vector's verdict therefore diverges between a conforming verifier and an omitting one:
result: invalid, flagMissingReductionForgery) — wrongly accepted by a verifier that omits the reduction.result: valid, flagMissingReductionFalseReject) — wrongly rejected by a verifier that omits the reduction.The file has one test group: a single ML-DSA-87 public key, two messages, and for each message a valid/forgery pair (4 tests total). Within a pair, the valid and forged signatures differ by a single byte (a hint flip), isolating the reduction behavior. A conforming verifier accepts all
validcases and rejects allinvalidcases; an implementation that omits the reduction gets at least one wrong.Validation
mldsa_verify_sls/vectorlint(valid: 1, invalid: 0; full suite unaffected).github.com/programsurf/mldsa-reduction-omission, version1.Responsible disclosure
The omission was observed in a real implementation. Responsible disclosure was completed before this submission: the issue was reported to the affected library's maintainers and the fix had been released. In accordance with CONTRIBUTING, these vectors are submitted only after the bug was fixed, and are published to guard against the same omission recurring in current or future verifiers.
Authors
Sunwoo Lee (@programsurf), Hyuk Lim (@lubroai), Seunghyun Yoon (@yoonsh) — Korea Institute of Energy Technology