SessionInitiationId
Identifies one X3DH session initiation: 32 bytes (see docs/session-lifecycle.md).
Version 2 (S1, every new initiation): SHA-256 over the canonical initiation transcript, which is also the session's ratchet associated data, so the ID is derived only from bytes the first message's AEAD authenticates:
u32 length | "KSecureMessage-SessionInitiation-v2" (UTF-8)
| u32 length | sender userId (UTF-8) | u32 length | sender deviceId (UTF-8)
| u32 length | recipient userId (UTF-8) | u32 length | recipient deviceId (UTF-8)
| initiatorIdentityKey[64] | responderIdentityKey[64] | ephemeralKey[64]
| signedPreKeyId:u32 | flag:u8 (0x00 absent, 0x01 present) | [oneTimePreKeyId:u32]The sender is the initiator. A relay that changes any of these bytes (including the signing half of the ephemeral key, a prekey ID or either address) makes the first message fail to decrypt, so it can never obtain a second valid ID for the same initiation.
Version 1 (milestones 6–25, kept for stored sessions and retired IDs only): SHA-256 over
u32 length of domain | domain (UTF-8, ProtocolConstants.SESSION_INITIATION_DOMAIN)
| initiatorIdentityKey[64] | responderIdentityKey[64] | ephemeralKey[64]
| signedPreKeyId:u32 | flag:u8 (0x00 absent, 0x01 present) | [oneTimePreKeyId:u32]whose ephemeral key signing half and prekey IDs are not authenticated by X3DH (finding F3). The two versions use different domains, so their IDs never coincide.
Integers are big-endian. Both sides of a session derive the same ID: the initiator from its own initiation, the responder from the PreKeyMessage and the envelope's addresses. Before acceptance an ID computed from a message is only a lookup key; it is trusted as a session's origin only after decryption with the matching transcript.
IDs are ordered unsigned-lexicographically. The order is used to pick the winner of a simultaneous initiation and says nothing about age.