QuipNetwork / QuipNetwork/quip-validator
quip-crypto-primitives: HKDF info is not suite-separated (two SHRINCS suites from one seed share a tree)
Nobody has claimed this yet.
- Dominant language
- Rust
- Stars
- 5.6k
- Forks
- 32
- PR merge metrics
- No merged PRs in 30d
Description
Code location: the
quip-crypto-primitivescrate and BABE integration in the QuipNetworkpolkadot-sdkfork (branch v0.2). Issues are disabled on that fork, so this is filed here on the consuming protocol repo.
Summary
quip-crypto-primitives derives component seeds with a fixed HKDF info (b"pq" and b"classical") that does not vary by hybrid suite. Two different suites derived from the same master seed get the same pq_seed and the same classical seed. For the lattice suites this is a key-reuse concern that domain separation at signing time covers in practice. For the proposed stateful hash-based suites (H5 = ed25519+SHRINCS, H6 = sr25519+SHRINCS) it is worse. An identical pq_seed yields a byte-identical SHRINCS signing key. Two independent signers then operate one stateful Merkle tree, reuse its one-time leaves, and compromise the key.
Detail
HKDF_PQ_INFO = b"pq"andHKDF_CLASSICAL_INFO = b"classical", fixed for every suite —quip/primitives/crypto/src/seed.rs:16-40(path on branch v0.2).derive_component_seeds(master_seed)returns the samepq_seedfor H5 and H6 (and for H1/H3). SHRINCSkeygen(pq_seed, maxSignatures)is deterministic, so H5 and H6 from one master seed sharestateful_sk_seed,stateful_prf_seed, the leaf secrets,stateful_root, and the commitment.- Each signer keeps its own leaf counter starting at 1 and advances it independently. When H5 signs message A at leaf 1 and H6 signs a different message B at leaf 1, two messages share one WOTS-C one-time leaf. Two signatures under one one-time leaf yield a forgery that breaks the SHRINCS component, and the composite drops to classical-only security with no signal.
- The ordinary one-master-seed backup pattern triggers this.
Fix
Bind the construction's suite label and profile into the HKDF info for both components:
classical_seed = HKDF-Expand(prk, info = "classical/" ‖ Label, L = 32)
pq_seed = HKDF-Expand(prk, info = "pq/" ‖ Label, L = 32)
with Label the construction's registry label such as hybrid-sr25519-shrincs-256s-v1. A SHRINCS key then becomes a function of (master_seed, suite, profile, maxSignatures), and two suites cannot map to one tree.
Found during the SHRINCS-hybrid spec review (companion to hybrid signature spec v2.0, section 9). H5/H6 are proposed and not yet implemented, so there is no current deployed exposure — but the derivation should be suite-separated before any stateful suite merges.
Contributor guide
No contributing guide indexed for this repository
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start at quip/primitives/crypto/src/seed.rs:16-40 and trace derive_component_seeds into the BABE integration in the v0.2 polkadot-sdk fork. Verify how suite labels and profiles reach HKDF, then confirm that H5 and H6 derived from one master seed no longer share SHRINCS state or classical component seeds.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- rust
- Domain
- cryptography, security
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Quiet
- Clarity
- Clearly specified
- Newbie friendliness
- 48/100