Expand description
Concord v2 key derivations — CORD-02 Appendix A. FROZEN.
Everything v2 addresses on the wire derives from a Community secret through one of the shapes below; changing any labeled byte re-addresses every prior event (“a breaking change re-labels and becomes a different universe”). The layout is locked by the golden vectors in the test module — minted by an independent implementation — treat those as the spec.
Construction (A.1): HKDF-SHA256(ikm=secret, salt=∅, info, L=32) where
info = utf8(label) || 0x00 || id[32] || epoch_be[8]?
idis ALWAYS present: 32 raw bytes, all-zeroes where a label has no meaningful id.- the epoch (u64 big-endian) is the ONLY omittable field: labels marked no-epoch omit the 8 bytes entirely.
- the
scalar_normalizeretry counter (A.3) appends AFTER whatever fields are present, starting at byte value 0. (v1’s equivalent starts its retry byte at 1 — the two conventions differ only in a ~2⁻¹²⁸ branch, but v2 follows the spec exactly.)
These are DISTINCT from v1’s vector-community/v1/* labels — the two
protocols are different address universes by construction. The one label the
specs share is the edition hash (vector-community/v1/edition,
community::version::EDITION_LABEL), which upstream froze verbatim.
Structs§
- Group
Key - A.2
group_key— a plane’s stream keypair. The x-only pubkey is the on-wire Stream address (theauthorsfilter), the secret key signs the plane’s wraps, and the NIP-44 self-ECDH conversation key encrypts them. Only a holder of the deriving secret can produce any of the three, so only members can even identify a plane’s traffic.
Constants§
- TOKEN_
LEN - The size of a public-invite unlock token (CORD-05 §2) — 16 bytes in v2 (v1 tokens were 32).
Functions§
- banlist_
locator - The community-wide Banlist coordinate.
- base_
rekey_ group_ key - The base-rotation rekey address for
new_epoch, keyed by the PRIOR community_root — the base has no stable key above it, so the prior root is the one handle every retained member holds through the rotation (CORD-06 §2/§3). - channel_
group_ key - A Channel’s Chat Plane group key.
secretis thecommunity_rootfor a Public Channel (at the root epoch) or the Channel’s independent key for a Private one (at its own channel epoch) — CORD-03 §1. The channel id in the derivation gives every Channel a distinct address regardless of which secret feeds it. - channel_
rekey_ group_ key - A private Channel’s rekey address for
new_epoch, keyed by the community_root the receiver already holds (CORD-06 §2) — root-keyed, not channel-keyed, so any member recovers any epoch’s rekey directly (no ratchet; epochs stay independently recoverable). - community_
id_ of community_id = sha256("concord/community" || owner_xonly || owner_salt)— a plain SHA-256 commitment, NOT the hkdf shape. Ownership is a property of the id itself: forging a different owner onto an existing id is a second-preimage on SHA-256. (This is the root fix for the v1 forgeable owner-attestation anchor.)- control_
group_ key - The Control Plane’s group key (community_root-keyed, community-id-bound).
- dissolved_
group_ key - The dissolution tombstone’s group key — derived from the community_id ALONE (no key, no epoch), so every member past or present resolves the same address and a Refounding can never strand the grave (CORD-02 §9).
- epoch_
key_ commitment sha256("concord/epoch-key-commitment" || prev_epoch_be[8] || prev_key[32])— theprevcommitcontinuity check on every rekey (CORD-06 §2). A convergence mechanism, never a secrecy one.- grant_
locator - A member’s Grant entity coordinate (the edition
eid). - guestbook_
group_ key - The Guestbook Plane’s group key (community_root-keyed, community-id-bound).
- invite_
bundle_ key - The public-invite bundle decrypt key, derived from the link’s 16-byte unlock token alone (CORD-05 §2).
- invite_
links_ locator - A creator’s invite-link Registry coordinate (CORD-05 §5) — bound to the creator so each creator owns exactly their own list.
- recipient_
locator - A rekey blob’s per-recipient locator (CORD-06 §2):
hkdf(rotator_xonly || recipient_xonly, "concord/recipient-pseudonym", scope_id, new_epoch). - verify_
community_ id - Verify a claimed
(owner, salt)pair reproducescommunity_id. Every bundle, pointer, and rehydrate path MUST pass this before trusting a claimed owner. - voice_
group_ key - A voice Channel’s SFU room keypair:
pkIS the room name,sksigns token grants. Same (secret, epoch) pair that addresses the Channel’s Chat Plane, so the room rolls exactly when the Channel’s key does. - voice_
media_ key - A voice Channel’s raw 32-byte media-encryption root — never feeds a cipher directly, every publisher’s per-sender frame key derives from it.
- voice_
sender_ key - A publisher’s per-sender frame key material:
hkdf(voice_media_key, "concord/voice-sender", sha256(utf8(identity)))— epoch omitted, the media key already carries it. Distinct per-sender keys partition the AEAD nonce domains.