adratchet

package
v0.0.0-...-bfa4f7b Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Aug 16, 2026 License: Apache-2.0, MIT Imports: 7 Imported by: 0

Documentation

Overview

Package adratchet implements an asynchronous double ratchet mechanism with Thyrse, X25519, and ML-KEM-768.

Hybrid ratchet steps alternate between the initiator and responder. A single root protocol absorbs each X25519 DH and ML-KEM shared secret and forks independent chain protocols; each chain in turn forks an independent protocol for every message.

Example
package main

import (
	"crypto/ecdh"
	"crypto/mlkem"
	"fmt"

	"github.com/codahale/thyrse"
	"github.com/codahale/thyrse/internal/testdata"
	"github.com/codahale/thyrse/schemes/complex/adratchet"
)

func main() {
	drbg := testdata.New("thyrse async double ratchet")

	// Bea publishes initial X25519 and ML-KEM keys.
	dB, qB := x25519KeyPair(drbg)
	kB, _ := mlkem.NewDecapsulationKey768(drbg.Data(mlkem.SeedSize))

	// Alice and Bea have a shared protocol state, probably thanks to an ECDH handshake.
	p := thyrse.New("example")
	p.Mix("shared key", []byte("ok then"))

	// Alice initiates the ratchet with her first message.
	a, msgA := adratchet.Initiate(
		p.Clone(), qB, kB.EncapsulationKey(), []byte("this is my first message"),
	)

	// Bea receives the first message and establishes her ratchet state.
	b, v, err := adratchet.Respond(p.Clone(), dB, kB, msgA)
	if err != nil {
		panic(err)
	}
	fmt.Printf("message from A: %q\n", v)

	// Bea sends Alice a message.
	msgB := b.SendMessage([]byte("no, this is _my_ first message"))

	// Alice reads Bea's message.
	v, err = a.ReceiveMessage(msgB)
	if err != nil {
		panic(err)
	}
	fmt.Printf("message from B: %q\n", v)

}

func x25519KeyPair(drbg *testdata.DRBG) (*ecdh.PrivateKey, *ecdh.PublicKey) {
	private, err := ecdh.X25519().NewPrivateKey(drbg.Data(32))
	if err != nil {
		panic(err)
	}
	return private, private.PublicKey()
}
Output:
message from A: "this is my first message"
message from B: "no, this is _my_ first message"

Index

Examples

Constants

View Source
const (
	// MaxSkip is the maximum number of skipped message states retained across all chains, as well as the maximum gap
	// accepted in a single chain.
	MaxSkip = 1000
	// Overhead is the number of bytes added to a message by State.SendMessage.
	Overhead = headerSize + thyrse.TagSize
)

Variables

This section is empty.

Functions

This section is empty.

Types

type State

type State struct {
	// contains filtered or unexported fields
}

State maintains the state of an asynchronous double ratchet.

func Initiate

func Initiate(
	p *thyrse.Protocol,
	remote *ecdh.PublicKey,
	remoteKEM *mlkem.EncapsulationKey768,
	plaintext []byte,
) (*State, []byte)

Initiate creates a double ratchet state for the initiating party and sends the first message using the responder's X25519 and ML-KEM public keys. The given root protocol is consumed by the returned state. Panics if the X25519 public key produces an invalid shared secret.

func Respond

func Respond(
	p *thyrse.Protocol,
	local *ecdh.PrivateKey,
	localKEM *mlkem.DecapsulationKey768,
	ciphertext []byte,
) (*State, []byte, error)

Respond receives the initiator's first message using the responder's X25519 and ML-KEM private keys and creates a double ratchet state. The given root protocol is consumed by the returned state on success and remains unchanged on failure. Returns an error if the message is invalid.

func (*State) ReceiveMessage

func (s *State) ReceiveMessage(ciphertext []byte) ([]byte, error)

ReceiveMessage decrypts the given ciphertext and returns the plaintext. It handles out-of-order messages and performs ratchet steps as needed. State changes are committed only after the message authenticates successfully.

func (*State) SendMessage

func (s *State) SendMessage(plaintext []byte) []byte

SendMessage encrypts the given plaintext and returns the ciphertext, which includes a header with the current ratchet state.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL