Skip to content

sign/mldsa: is the pointer-sharing of sk.tr into the pk returned by (*PrivateKey).Public() intentional? #600

@bshastry

Description

@bshastry

Question-shaped report, not a vulnerability claim. Reading this alongside NewKeyFromSeed (same file, :240), the most plausible explanation is an intentional micro-optimization — avoiding a pkEncode + SHAKE256(·, 64) on every Public() call. A one-line rationale in a comment would give future auditors something concrete to cite. If you'd prefer to address it, the fix is a one-line value copy (pk.tr = sk.tr) — happy to send a CL.

Observation

sign/mldsa/mldsa65/internal/dilithium.go:474-485:

func (sk *PrivateKey) Public() *PublicKey {
    var t0 VecK
    pk := &PublicKey{
        rho: sk.rho,
        A:   &sk.A,
        tr:  &sk.tr,        // pointer-shared with sk.tr
    }
    sk.computeT0andT1(&t0, &pk.t1)
    pk.t1.PackT1(pk.t1p[:])
    return pk
}

PublicKey.UnmarshalBinary at :115-128 recomputes tr = SHAKE256(pk_bytes, 64) honestly. So the same pk has two tr states: one from Public() (aliased to sk.tr), one from Pack → UnmarshalBinary (recomputed). Signatures produced under a mutated sk.tr verify against the former, fail against the latter.

Spec reading

FIPS 204 Alg. 6 step 9 defines tr ← H(pkEncode(ρ, t1), 64) — a computed value. The SK-stored copy is a cache. Aliasing lets any divergence in sk.tr (including #581's unvalidated parse path) silently shape the derived pk.

Reach

(*PrivateKey).Public() is crypto.Signer's public interface.

What would be useful

Any of:

  • "Intentional — here's why" (most likely; close WAI, comment welcome).
  • "Worth tightening — patch welcome" (one-line pk.tr = sk.tr value copy).
  • "Reproducer first" (reproducer available).

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions