Package-level declarations

Types

Link copied to clipboard

Content commitment of an application message body, version 1 (docs/application-delivery.md). A client keeps it with a committed inbound message so that a later message with the same logical ID but another body is detected instead of acknowledged. Local storage only: it is never sent and is not part of any wire format.

Link copied to clipboard

KSecureMessage ciphertext wire format, version 1. The output goes into EncryptedEnvelope.payload. Framing only: no cryptography happens here and the ratchet bytes are carried unchanged. Full specification: docs/wire-format.md.

Link copied to clipboard
data class DecryptionResult(val plaintext: ByteArray, val updatedSession: SecureSession)
Link copied to clipboard
class DeviceAuthenticationKeyPair(val publicKey: ByteArray, val privateKey: ByteArray)

The local device's authentication key pair: a 32-byte Ed25519 seed and the 32-byte Ed25519 public key. Created by ProtocolEngine.createDeviceAuthenticationKey. The private key never leaves the device; the server only gets publicKey. A plain class, so toString() never prints key bytes.

Link copied to clipboard

Routine device authentication key rotation, format version 1 (docs/device-authentication-rotation.md). All three constructions share the rotation statement:

class DeviceAuthenticationRotationAuthorization(val statement: DeviceAuthenticationRotationStatement, authorizationSignature: ByteArray, proofOfPossession: ByteArray)

A statement with both proofs: authorizationSignature by the current key, proofOfPossession by the replacement key.

Link copied to clipboard

Identifies one rotation statement: 32 bytes, SHA-256 over the domain KSecureMessage-DeviceAuthRotationId-v1 and the statement. The server records the ID of the rotation that installed a device's current key, so a retry of the same rotation is recognized. It is never an authorization.

Link copied to clipboard
class DeviceAuthenticationRotationStatement(val address: DeviceAddress, currentPublicKey: ByteArray, replacementPublicKey: ByteArray, val expectedAuthEpoch: Long, val timestamp: Instant, val nonce: RequestNonce)

The transition a routine rotation asks for: address's registered key currentPublicKey at authentication epoch expectedAuthEpoch is to be replaced by replacementPublicKey. timestamp (whole milliseconds) and nonce make each statement single-use.

Link copied to clipboard

Device recovery format version 1 (docs/device-recovery.md). All three constructions share the recovery statement:

Link copied to clipboard
class DeviceRecoveryAuthorization(val request: DeviceRecoveryRequest, authorizerSignature: ByteArray)

A request authorized by its DeviceRecoveryRequest.authorizer: authorizerSignature is the authorizer's device authentication key's signature over the recovery statement. Carries both proofs; the target device submits it to the server.

Link copied to clipboard

Transfer encoding of recovery requests and authorizations, version 1, for applications that move them between devices (QR code, file, their own channel). Not signed as such: the signatures inside cover the statement.

Link copied to clipboard

Identifies one recovery statement: 32 bytes, SHA-256 over the domain KSecureMessage-DeviceRecoveryId-v1 and the statement. The server records the ID of the recovery that installed a device's current key, so a retry of the same recovery is recognized. It is never an authorization.

Link copied to clipboard
class DeviceRecoveryRequest(val target: DeviceAddress, val authorizer: DeviceAddress, replacementPublicKey: ByteArray, val timestamp: Instant, val nonce: RequestNonce, proofOfPossession: ByteArray)

A device's request to replace its registered device authentication key with replacementPublicKey, to be authorized by authorizer, another device of the same user. proofOfPossession is the replacement key's signature over the recovery statement (DeviceRecovery), so the request cannot name a key its sender does not hold.

Link copied to clipboard
data class EncryptionResult(val message: CiphertextMessage, val updatedSession: SecureSession)
Link copied to clipboard

ProtocolEngine backed by Kodium's X3DH and Double Ratchet.

Link copied to clipboard

Last-device recovery, format version 1 (docs/last-device-recovery.md). Recovery statement:

Link copied to clipboard
class LastDeviceRecoveryAuthorization(val statement: LastDeviceRecoveryStatement, recoverySignature: ByteArray, proofOfPossession: ByteArray)

A statement with both proofs: recoverySignature by the offline recovery key, proofOfPossession by the replacement key.

Link copied to clipboard
class LastDeviceRecoveryChallenge(val target: DeviceAddress, val id: LastDeviceRecoveryChallengeId, nonce: ByteArray, val authEpoch: Long, val expiresAt: Instant)

A server-issued, single-use challenge for recovering target: the random id and nonce, the target's authentication epoch authEpoch when the challenge was issued, and expiresAt (whole milliseconds, server clock). Contains no secret; the recovery is bound to it by the signatures.

Link copied to clipboard

Server-chosen identifier of one last-device recovery challenge: 16 random bytes. Not secret.

Link copied to clipboard

Identifies one last-device recovery statement: 32 bytes, SHA-256 over the domain KSecureMessage-LastDeviceRecoveryId-v1 and the statement. The server records the ID of the recovery that installed a device's current key, so a retry of the same recovery is recognized. Never an authorization.

Link copied to clipboard

The offline last-device recovery key of a user: a 32-byte Ed25519 seed and its 32-byte public key. Created by ProtocolEngine.createLastDeviceRecoveryKey; the application keeps it offline (for example printed or in a password manager) in the canonical text form encode. Only publicKey is ever sent to the server. The library never persists it.

Link copied to clipboard
class LastDeviceRecoveryKeyRegistration(val userId: UserId, publicKey: ByteArray, proofOfPossession: ByteArray)

A user's registration of publicKey as its last-device recovery key. proofOfPossession is the recovery key's signature over u32 length | domain | u32 length | userId | publicKey, so nobody can register a key they do not hold (a registration cannot be replaced in milestone 18).

Link copied to clipboard
class LastDeviceRecoveryStatement(val challenge: LastDeviceRecoveryChallenge, recoveryPublicKey: ByteArray, replacementPublicKey: ByteArray)

The transition a last-device recovery asks for: challenge's target, at the challenge's epoch, gets replacementPublicKey, authorized by the recovery key recoveryPublicKey. The replacement key must differ from the recovery key.

Link copied to clipboard
class LocalIdentity(val publicKey: ByteArray, val privateKey: ByteArray)

Long-term identity key pair of the local device.

Link copied to clipboard
class OneTimePreKeyPair(val id: OneTimePreKeyId, val publicKey: ByteArray, val privateKey: ByteArray)

One-time prekey pair. Delete the private key after a session was accepted with it (see SessionAcceptanceResult.consumedOneTimePreKeyId).

Link copied to clipboard

Shape of the public prekey material KSecureMessage publishes. Lets code outside the protocol engine (the server, transports) check untrusted publications without Kodium. This is a format check only: it does not verify the signed prekey signature, which initiators do before X3DH.

Link copied to clipboard
interface ProtocolEngine

High-level protocol boundary implemented with Kodium.

Link copied to clipboard

Failures raised by a ProtocolEngine. Messages never contain key material. The underlying cause is kept for debugging.

Link copied to clipboard

The public messaging identity key of a device: SIZE bytes (X25519 key followed by Ed25519 key), as in a prekey bundle. Immutable: the bytes are copied in and out.

Link copied to clipboard

Delayed recovery key reset, format version 1 (docs/recovery-key-reset.md). Integers are big-endian, strings u32 length | UTF-8.

A cancellation statement with the current recovery key's signature.

Link copied to clipboard
class RecoveryKeyResetCancellationStatement(val userId: UserId, val resetId: RecoveryKeyResetId, val expectedEpoch: Long, currentPublicKey: ByteArray, val requestedAt: Instant, val eligibleAt: Instant)

The cancellation of the pending reset resetId of userId's recovery key currentPublicKey at expectedEpoch (requested at requestedAt, eligible from eligibleAt) by that recovery key itself.

Link copied to clipboard

A completion statement with the new recovery key's newKeyProofOfPossession.

Link copied to clipboard

Identifies one reset completion statement: 32 bytes, SHA-256 over the domain KSecureMessage-RecoveryKeyResetId-v1 and the statement. The server records the ID of the completion that installed the current recovery key, so a retry of the same completion is recognized. Never an authorization. Not the server-chosen RecoveryKeyResetId of the pending reset.

Link copied to clipboard
class RecoveryKeyResetCompletionStatement(val userId: UserId, val resetId: RecoveryKeyResetId, val expectedEpoch: Long, currentPublicKey: ByteArray, newPublicKey: ByteArray, val requestedAt: Instant, val eligibleAt: Instant, val completer: DeviceAddress)

The completion of the pending reset resetId of userId's recovery key currentPublicKey at recovery key epoch expectedEpoch, requested at requestedAt and eligible from eligibleAt (both server times, whole milliseconds), with newPublicKey, by the registered device completer of the same user.

Link copied to clipboard

A status query statement with the current recovery key's signature.

Link copied to clipboard
class RecoveryKeyResetStatusQueryStatement(val userId: UserId, currentPublicKey: ByteArray, val timestamp: Instant)

A query for userId's pending reset by the holder of its current recovery key currentPublicKey at timestamp (whole milliseconds, checked against the server clock with RecoveryKeyReset.VALIDITY_WINDOW).

Link copied to clipboard

Recovery key revocation, format version 1 (docs/recovery-key-lifecycle.md). Revocation statement:

Link copied to clipboard

A statement with the current recovery key's signature.

Link copied to clipboard

Identifies one recovery key revocation statement: 32 bytes, SHA-256 over the domain KSecureMessage-RecoveryKeyRevocationId-v1 and the statement. Never an authorization.

Link copied to clipboard
class RecoveryKeyRevocationStatement(val userId: UserId, val authorizer: DeviceAddress, currentPublicKey: ByteArray, val expectedEpoch: Long, val timestamp: Instant, val nonce: RequestNonce)

The revocation a user asks for: userId's recovery key currentPublicKey, registered at recovery key epoch expectedEpoch, is to be removed without a replacement, authorized by the device authorizer of the same user.

Link copied to clipboard

Recovery key rotation, format version 1 (docs/recovery-key-lifecycle.md). Rotation statement:

Link copied to clipboard
class RecoveryKeyRotationAuthorization(val statement: RecoveryKeyRotationStatement, currentKeySignature: ByteArray, newKeyProofOfPossession: ByteArray)

A statement with both proofs: currentKeySignature by the current recovery key, newKeyProofOfPossession by the new recovery key.

Link copied to clipboard

Identifies one recovery key rotation statement: 32 bytes, SHA-256 over the domain KSecureMessage-RecoveryKeyRotationId-v1 and the statement. The server records the ID of the rotation that installed the current recovery key, so a retry of the same rotation is recognized. Never an authorization.

Link copied to clipboard
class RecoveryKeyRotationStatement(val userId: UserId, val authorizer: DeviceAddress, currentPublicKey: ByteArray, newPublicKey: ByteArray, val expectedEpoch: Long, val timestamp: Instant, val nonce: RequestNonce)

The rotation a user asks for: userId's recovery key currentPublicKey, registered at recovery key epoch expectedEpoch, is to be replaced by newPublicKey, authorized by the device authorizer of the same user. timestamp (whole milliseconds) and nonce make each statement single-use.

Link copied to clipboard
class RequestAuthentication(val timestamp: Instant, val nonce: RequestNonce, signature: ByteArray)

The authentication a device attaches to a ServerRequest: when it was made (epoch milliseconds, no finer), a fresh nonce and the Ed25519 signature over ServerRequestAuthentication.canonicalInput.

Link copied to clipboard
class RequestNonce(bytes: ByteArray)

Single-use value of one authenticated request: SIZE random bytes. The server accepts each nonce once per device within the validity window.

Link copied to clipboard

The raw safety number: SHA-256 over both devices' addresses and identity keys, SIZE bytes.

Link copied to clipboard

Safety number version 1 of two devices (docs/identity-verification.md).

Link copied to clipboard

Machine-readable safety number payload, version 1, for a QR code or any other channel the application picks. Both devices produce identical bytes.

Link copied to clipboard

Result of comparing a local SafetyNumber with one scanned from the other device.

Link copied to clipboard
class SafetyNumberPayload(val first: DeviceAddress, val second: DeviceAddress, val fingerprint: SafetyFingerprint)

A decoded verification payload: the two devices in canonical order and their fingerprint. Decoding proves nothing; compare it with SafetyNumber.compare.

Link copied to clipboard
sealed interface SecurePayload

Content of one decrypted KSecureMessage message: the reliability frame that is the ratchet plaintext (docs/message-reliability.md). It is encrypted, so the server never sees it.

Link copied to clipboard

Reliability frame format, version 1. Its output is the plaintext handed to ProtocolEngine.encrypt; the ciphertext wire format (CiphertextMessageCodec) is not affected. Full specification: docs/message-reliability.md.

Link copied to clipboard
data class SecureSession(val remote: DeviceAddress, val state: ByteArray)

Persisted state of one end-to-end session with remote.

Link copied to clipboard

Canonical paths of the device-scoped HTTP API v1. The client builds its request URLs from them; the server rebuilds them from the decoded route parameters. Signatures cover these paths, never a raw request URI.

Link copied to clipboard
class ServerRequest(val address: DeviceAddress, val method: String, val path: String, val body: ByteArray)

What an authenticated request is about: the device it acts for, the HTTP method, the canonical path (ServerApiPaths) and the exact bytes of the HTTP request body (empty for a request without body).

Link copied to clipboard

Signs and verifies server requests with a device authentication key, format version 1 (docs/server-authentication.md). The signed input is:

Link copied to clipboard
data class SessionAcceptanceResult(val session: SecureSession, val plaintext: ByteArray, val consumedOneTimePreKeyId: OneTimePreKeyId?)
Link copied to clipboard
class SessionInfo(val initiationId: SessionInitiationId?, val awaitingReply: Boolean, val acceptedSignedPreKeyId: SignedPreKeyId? = null, val initiationVersion: SessionInitiationVersion = SessionInitiationVersion.V2)

Lifecycle facts about a stored session, see docs/session-lifecycle.md.

Link copied to clipboard

Identifies one X3DH session initiation: 32 bytes (see docs/session-lifecycle.md).

Link copied to clipboard
class SignedPreKeyPair(val id: SignedPreKeyId, val publicKey: ByteArray, val signature: ByteArray, val privateKey: ByteArray)

Signed prekey pair. signature is the identity key's signature over publicKey. Keep the private key until the signed prekey is rotated out and no more session-setup messages for it are expected.

Link copied to clipboard

Whether the user confirmed a pinned remote identity out of band (docs/identity-verification.md).