Documentation
¶
Overview ¶
Package spqr implements Signal's Sparse Post-Quantum Ratchet (SPQR), the Stage-2 post-quantum layer that augments the Double Ratchet with chunked ML-KEM-768 key agreement. It is a pure-Go port of the SPQR reference crate (sparsepostquantumratchet v1.5.1) layered on the incremental ML-KEM-768 KEM in internal/mlkem768incr.
This file is Slice A: the ratchet-state codec. A SPQR ratchet state is serialized as the signal.proto.pq_ratchet.PqRatchetState protobuf — version negotiation, the Double-Ratchet-style epoch Chain, and a V1State holding the in-flight incremental-KEM artifacts (header, encaps key, encaps state, ciphertexts) plus the chunk-transport encoder/decoder state. The codec is a transparent byte round-trip over that proto: it stores and returns the exact bytes, performing no normalization (the libcrux issue-1275 endianness fix lives in the encapsulate2 path, not here). The chunked transport (Slice B) and the send/recv state machine (Slice C) build on this codec.
Index ¶
- Constants
- Variables
- func CurrentVersion(b SerializedState) (proto.Version, error)
- func DecodeState(b SerializedState) (*proto.PqRatchetState, error)
- func EmbeddedEncapsState(st *proto.PqRatchetState) ([]byte, bool)
- func ResolveMaxJump(p *proto.ChainParams) uint32
- type EpochSecret
- type Params
- type RecvResult
- type SendResult
- type SerializedMessage
- type SerializedState
- type VersionStatus
Constants ¶
const DefaultMaxJump uint32 = 25000
DefaultMaxJump is the SPQR Chain's default cap on how far ahead of the current counter a message key may be requested; a stored ChainParams.max_jump of 0 resolves to this. It matches the protocol-wide forward-jump cap (the same 25000 value as the Double Ratchet / sender-key bound, groups.MaxForwardJumps); SPQR carries it as its own ChainParams field (proto pq_ratchet ChainParams), so it is named here rather than imported across the domain boundary.
Variables ¶
var ( // ErrInvalidCtMac is returned when a ciphertext MAC does not verify. // Mirrors Error::InvalidCtMac. ErrInvalidCtMac = errors.New("spqr: ciphertext MAC is invalid") // ErrInvalidHdrMac is returned when an encapsulation-key header MAC does not // verify. Mirrors Error::InvalidHdrMac. ErrInvalidHdrMac = errors.New("spqr: encapsulation-key header MAC is invalid") )
Authenticator MAC-verification errors, mirroring authenticator.rs Error.
var ( // ErrKeyJump is returned when a requested key index is more than max_jump // ahead of the current counter. Mirrors Error::KeyJump. ErrKeyJump = errors.New("spqr: requested key too far ahead (max jump)") // ErrKeyTrimmed is returned when a requested out-of-order key is older than // the retention window. Mirrors Error::KeyTrimmed. ErrKeyTrimmed = errors.New("spqr: requested key already trimmed (too old)") // ErrKeyAlreadyRequested is returned when a key index was already consumed. // Mirrors Error::KeyAlreadyRequested. ErrKeyAlreadyRequested = errors.New("spqr: key already requested") // ErrEpochOutOfRange is returned for an epoch not in the retained window. // Mirrors Error::EpochOutOfRange. ErrEpochOutOfRange = errors.New("spqr: epoch out of range") // ErrSendKeyEpochDecreased is returned when send_key is asked for an epoch // older than the current send epoch. Mirrors Error::SendKeyEpochDecreased. ErrSendKeyEpochDecreased = errors.New("spqr: send key epoch decreased") // ErrChainDecode is returned when a Chain proto is structurally invalid. // Mirrors Error::StateDecode in the chain context. ErrChainDecode = errors.New("spqr: invalid chain state") )
Chain errors, mirroring the relevant chain.rs Error variants.
var ( // ErrVersionMismatch is returned when a peer presents a lower version than // ours and we are not allowed to negotiate. Mirrors Error::VersionMismatch. ErrVersionMismatch = errors.New("spqr: version mismatch after negotiation") // ErrMinimumVersion is returned when a peer's version is below our configured // minimum. Mirrors Error::MinimumVersion. ErrMinimumVersion = errors.New("spqr: peer version below minimum") // ErrChainNotAvailable is returned when a V1 state needs its Chain but none is // present and no version-negotiation block can build one. Mirrors // Error::ChainNotAvailable. ErrChainNotAvailable = errors.New("spqr: chain not available") )
Orchestration errors, mirroring the relevant lib.rs Error variants.
var ( // ErrEpochOutOfRangeV1 is returned when a received message's epoch is ahead // of the state's. Mirrors Error::EpochOutOfRange in the v1 dispatch. ErrEpochOutOfRangeV1 = errors.New("spqr: v1 message epoch out of range") // ErrErroneousData is returned when a received ek does not match the header // it should correspond to. Mirrors Error::ErroneousDataReceived. ErrErroneousData = errors.New("spqr: erroneous data received") )
v1 errors mirroring the relevant reference Error variants.
var ( // ErrInvalidState is returned when a serialized state cannot be decoded as a // PqRatchetState protobuf. ErrInvalidState = errors.New("spqr: invalid serialized state") )
Errors returned by the state codec, %w-wrappable and errors.Is-matchable.
var ErrMsgDecode = errors.New("spqr: invalid serialized message")
ErrMsgDecode is returned when a serialized v1 message is malformed (wrong version byte, zero/absent epoch, truncated chunk, or an unknown message type). Mirrors the reference Error::MsgDecode.
var ErrV1StateDecode = errors.New("spqr: invalid v1 state")
ErrV1StateDecode is returned when a proto.V1State cannot be decoded into a v1State (missing inner variant, missing required sub-message, or a malformed encoder/decoder). Mirrors the reference Error::StateDecode.
Functions ¶
func CurrentVersion ¶
func CurrentVersion(b SerializedState) (proto.Version, error)
CurrentVersion reports the SPQR version a serialized state is operating at. A state with no inner is V0 (SPQR disabled); a V1State inner is V1. Mirrors the reference current_version (the version-negotiation detail — whether negotiation is still in progress — is a Slice C concern and not decoded here).
func DecodeState ¶
func DecodeState(b SerializedState) (*proto.PqRatchetState, error)
DecodeState parses a serialized state into the generated PqRatchetState proto. An empty input decodes to a zero PqRatchetState (V0). Malformed input returns ErrInvalidState and never panics.
func EmbeddedEncapsState ¶
func EmbeddedEncapsState(st *proto.PqRatchetState) ([]byte, bool)
EmbeddedEncapsState returns the incremental-KEM EncapsState (es) bytes carried by the state's current V1State variant, or (nil, false) when the variant holds no es. The send_ct side stores an es between encapsulate1 and encapsulate2; it lives in the Ct1Sent / Ct1SentEkReceived unchunked states (reached via the Ct1Sampled, Ct1Acknowledged, and EkReceivedCt1Sampled chunked variants).
The bytes are returned verbatim, exactly as stored — possibly carrying the libcrux issue-1275 swapped endianness. The codec never normalizes them; the encapsulate2 path (mlkem768incr.FixEncapsStateEndianness) does, just before use. This accessor lets that path (Slice C) and the codec's own round-trip test reach the embedded es.
func ResolveMaxJump ¶
func ResolveMaxJump(p *proto.ChainParams) uint32
ResolveMaxJump returns the effective max-jump cap for a ChainParams: the stored value, or DefaultMaxJump when it is zero (the proto default). Mirrors the reference "if zero, defaults to 25,000".
Types ¶
type EpochSecret ¶
EpochSecret is a per-epoch shared secret the Double Ratchet should mix into its key schedule. (Exposed at the package boundary; internally the v1 machine and Chain pass the unexported epochSecret.)
type Params ¶
type Params struct {
Direction proto.Direction
Version proto.Version
MinVersion proto.Version
AuthKey []byte
ChainParams *proto.ChainParams
}
Params configures a fresh SPQR state. Mirrors lib.rs Params.
type RecvResult ¶
type RecvResult struct {
State SerializedState
Key []byte // nil when no message key was produced
}
RecvResult is the output of Recv: the new serialized state and an optional message key.
func Recv ¶
func Recv(state SerializedState, msg SerializedMessage) (*RecvResult, error)
Recv folds an inbound SPQR message into the state. It first performs version negotiation (a lower-version message may downgrade us, or be rejected), then drives the v1 recv step, folds any epoch secret into the Chain, and derives the message key. Mirrors lib.rs recv.
type SendResult ¶
type SendResult struct {
State SerializedState
Msg SerializedMessage
Key []byte // nil when no message key was produced
}
SendResult is the output of Send: the new serialized state, the message to transmit, and an optional message key produced this step.
func Send ¶
func Send(state SerializedState, rng io.Reader) (*SendResult, error)
Send produces the next outbound SPQR message and the updated state. For a V0 state it returns empty state/msg and no key. Mirrors lib.rs send.
type SerializedMessage ¶
type SerializedMessage = []byte
SerializedMessage is a SPQR message in wire form (the v1 message codec bytes; empty for V0).
type SerializedState ¶
type SerializedState = []byte
SerializedState is a SPQR ratchet state in its wire/storage form: the PqRatchetState protobuf bytes. The empty slice is the initial "no SPQR yet" state (libcrux empty_state()).
func EmptyState ¶
func EmptyState() SerializedState
EmptyState returns the initial serialized state: empty bytes. Decoding it yields a PqRatchetState with no inner version (V0 / SPQR disabled), matching the reference empty_state().
func EncodeState ¶
func EncodeState(st *proto.PqRatchetState) (SerializedState, error)
EncodeState serializes a PqRatchetState back to its wire bytes. For a state obtained from DecodeState and left unmodified, this reproduces the input bytes exactly (the codec is a transparent byte round-trip — see the package doc and the fixture round-trip test).
func InitialState ¶
func InitialState(p Params) (SerializedState, error)
InitialState builds the initial serialized state for the given params. V0 yields the empty state; V1 yields a PqRatchetState with the role's initial v1 inner state and a version-negotiation block. Mirrors lib.rs initial_state.
type VersionStatus ¶
type VersionStatus struct {
Negotiating bool
Version proto.Version // the active/proposed version
MinVersion proto.Version // valid only while Negotiating
}
VersionStatus reports a state's negotiation status. Mirrors lib.rs CurrentVersion: either still negotiating (with the proposed and minimum versions) or negotiation complete (at a fixed version).
func Negotiation ¶
func Negotiation(b SerializedState) (VersionStatus, error)
Negotiation reports the negotiation status of a serialized state. Mirrors lib.rs current_version.