From 994071243fc80990cf09e820b671006e9bd31c76 Mon Sep 17 00:00:00 2001 From: Gab <24553253+gabrix73@users.noreply.github.com> Date: Thu, 13 Aug 2026 14:04:30 +0200 Subject: Separate active YAMN code from Katzenpost PoC --- katzenpost/dispatcher/frame.go | 84 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 84 insertions(+) create mode 100644 katzenpost/dispatcher/frame.go (limited to 'katzenpost/dispatcher/frame.go') diff --git a/katzenpost/dispatcher/frame.go b/katzenpost/dispatcher/frame.go new file mode 100644 index 0000000..43f547c --- /dev/null +++ b/katzenpost/dispatcher/frame.go @@ -0,0 +1,84 @@ +package dispatcher + +import ( + "crypto/rand" + "crypto/sha256" + "errors" + "fmt" + + "github.com/fxamacker/cbor/v2" +) + +const ( + ProtocolVersion = 1 + MaxSphinxPayload = 2000 + FrameDataBytes = 1500 + MaxFrames = (MaxEnvelopeBytes + FrameDataBytes - 1) / FrameDataBytes +) + +type Frame struct { + Version uint8 `cbor:"1,keyasint"` + ID [16]byte `cbor:"2,keyasint"` + Digest [32]byte `cbor:"3,keyasint"` + Index uint16 `cbor:"4,keyasint"` + Total uint16 `cbor:"5,keyasint"` + Data []byte `cbor:"6,keyasint"` +} + +func SplitEnvelope(encoded []byte) ([][]byte, error) { + if len(encoded) == 0 || len(encoded) > MaxEnvelopeBytes { + return nil, errors.New("invalid encoded envelope size") + } + + var id [16]byte + if _, err := rand.Read(id[:]); err != nil { + return nil, fmt.Errorf("generate message id: %w", err) + } + digest := sha256.Sum256(encoded) + total := (len(encoded) + FrameDataBytes - 1) / FrameDataBytes + if total > MaxFrames { + return nil, errors.New("encoded envelope requires too many frames") + } + + frames := make([][]byte, 0, total) + for index, start := 0, 0; start < len(encoded); index, start = index+1, start+FrameDataBytes { + end := min(start+FrameDataBytes, len(encoded)) + frame := Frame{ + Version: ProtocolVersion, + ID: id, + Digest: digest, + Index: uint16(index), + Total: uint16(total), + Data: encoded[start:end], + } + payload, err := cbor.Marshal(frame) + if err != nil { + return nil, fmt.Errorf("encode frame %d: %w", index, err) + } + if len(payload) > MaxSphinxPayload { + return nil, fmt.Errorf("frame %d exceeds Sphinx payload limit", index) + } + frames = append(frames, payload) + } + return frames, nil +} + +func DecodeFrame(payload []byte) (Frame, error) { + if len(payload) == 0 || len(payload) > MaxSphinxPayload { + return Frame{}, errors.New("invalid frame size") + } + var frame Frame + if err := cbor.Unmarshal(payload, &frame); err != nil { + return Frame{}, fmt.Errorf("decode frame: %w", err) + } + if frame.Version != ProtocolVersion { + return Frame{}, errors.New("unsupported frame version") + } + if frame.Total == 0 || int(frame.Total) > MaxFrames || frame.Index >= frame.Total { + return Frame{}, errors.New("invalid frame sequence") + } + if len(frame.Data) == 0 || len(frame.Data) > FrameDataBytes { + return Frame{}, errors.New("invalid frame data size") + } + return frame, nil +} -- cgit v1.2.3