casket

package module
v0.1.0 Latest Latest
Warning

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

Go to latest
Published: May 15, 2026 License: Apache-2.0 Imports: 15 Imported by: 0

README

casket-go

CI Release Go Reference License

Go port of casket-ts channel.ts — Ed25519 + ECDH channel identity for Frame-to-Frame relay.

Cross-compatible wire format with casket-ts (Node.js / Cloudflare Workers) and casket-dotnet (.NET).

License

Apache-2.0. See LICENSE.

Documentation

Overview

Package casket provides Ed25519 + ECDH channel identity for Frame-to-Frame relay.

Each Frame holds two keypairs:

  • Ed25519 (signing/verification) — non-repudiation on outer envelope
  • ECDH (P-256 or X25519) — derives a shared symmetric key for body encryption

Wire format and JSON shapes are byte-identical to casket-ts/src/channel.ts so a Go Frame and a TS Frame can pair through the interchange and interop byte-for-byte.

Index

Constants

This section is empty.

Variables

View Source
var (
	ErrChannelPair    = errors.New("channel pair error")
	ErrChannelVerify  = errors.New("channel verify error")
	ErrChannelDecrypt = errors.New("channel decrypt error")
)

Sentinel errors — use errors.Is to test.

Functions

func DeriveAgentKey

func DeriveAgentKey(seed []byte, slug string) (ed25519.PrivateKey, ed25519.PublicKey, error)

DeriveAgentKey derives a deterministic Ed25519 keypair from an owner's identity seed and an agent slug. See package doc for details.

Errors: returns an error if seed is empty or slug is empty.

Types

type Channel

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

Channel is a Frame's local identity. One per Nexus instance. Call Load on every cold start — generates keys on first run, reloads on subsequent runs.

func Load

func Load(ctx context.Context, nexusID string, storage ChannelStorage, dhAlg DhAlgorithm) (*Channel, error)

Load initialises the Channel from storage, generating keys on first run. dhAlg is ignored on reload — the stored algorithm is authoritative.

func (*Channel) DHAlg

func (c *Channel) DHAlg() DhAlgorithm

func (*Channel) DHPublicKeyB64u

func (c *Channel) DHPublicKeyB64u() string

func (*Channel) DHPublicKeyBytes

func (c *Channel) DHPublicKeyBytes() []byte

func (*Channel) GetPaired

func (c *Channel) GetPaired(ctx context.Context, peerID string) (*PairedChannel, error)

GetPaired reloads an existing PairedChannel from storage. Returns nil, nil if the peer is not found.

func (*Channel) MakePairingToken

func (c *Channel) MakePairingToken(endpoint string) PairingToken

MakePairingToken builds a PairingToken to exchange OOB with the peer operator.

func (*Channel) Pair

func (c *Channel) Pair(ctx context.Context, token PairingToken, maxAgeSec int64) (*PairedChannel, error)

Pair completes pairing from the peer's PairingToken. Derives the shared AEAD key via ECDH and stores the peer record. Returns ErrChannelPair if the token is stale, malformed, or uses a mismatched algorithm.

func (*Channel) PublicKeyB64u

func (c *Channel) PublicKeyB64u() string

func (*Channel) PublicKeyBytes

func (c *Channel) PublicKeyBytes() []byte

func (*Channel) Revoke

func (c *Channel) Revoke(ctx context.Context, peerID string) error

Revoke removes a peer from storage. A fresh Pair after revocation produces a new pathID.

func (*Channel) Sign

func (c *Channel) Sign(data []byte) ([]byte, error)

Sign signs arbitrary bytes with the channel's own Ed25519 key. Use for pre-pairing operations (e.g. self-sig on a pairing half) where no PairedChannel exists yet. Returns the raw 64-byte signature.

type ChannelStorage

type ChannelStorage interface {
	Get(ctx context.Context, key string) (string, error)
	Put(ctx context.Context, key, value string) error
	Delete(ctx context.Context, key string) error
}

ChannelStorage is the persistence interface injected into a Channel. Returning ("", nil) from Get signals key-not-found.

type DhAlgorithm

type DhAlgorithm string

DhAlgorithm is the ECDH curve used for key exchange.

const (
	P256   DhAlgorithm = "P-256"
	X25519 DhAlgorithm = "X25519"
)

type PairedChannel

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

PairedChannel is an active channel to a specific peer. Obtained from Channel.Pair or Channel.GetPaired.

func (*PairedChannel) DecryptBody

func (p *PairedChannel) DecryptBody(blob, aad []byte) ([]byte, error)

DecryptBody decrypts a blob produced by EncryptBody. blob layout: nonce (12 bytes) || ciphertext+GCM-tag. Returns ErrChannelDecrypt if authentication fails or blob is too short.

func (*PairedChannel) EncryptBody

func (p *PairedChannel) EncryptBody(plaintext, aad []byte) ([]byte, error)

EncryptBody encrypts the message body (inner layer) with AES-256-GCM. Returns nonce (12 bytes) || ciphertext+GCM-tag as raw bytes. aad is optional additional authenticated data. Output format matches casket-ts encryptBody exactly.

func (*PairedChannel) PathID

func (p *PairedChannel) PathID() string

func (*PairedChannel) PeerEndpoint

func (p *PairedChannel) PeerEndpoint() string

func (*PairedChannel) PeerID

func (p *PairedChannel) PeerID() string

func (*PairedChannel) PeerRecord

func (p *PairedChannel) PeerRecord() PeerRecord

func (*PairedChannel) Sign

func (p *PairedChannel) Sign(data []byte) ([]byte, error)

Sign signs arbitrary bytes for the outer envelope using the local Ed25519 key. Returns the raw 64-byte signature.

func (*PairedChannel) Verify

func (p *PairedChannel) Verify(sig, data []byte) error

Verify verifies a signature from the peer. Returns ErrChannelVerify if the signature is invalid.

type PairingToken

type PairingToken struct {
	V        int         `json:"v"` // always 1
	NexusID  string      `json:"nexus_id"`
	SigAlg   string      `json:"sig_alg"` // always "ed25519"
	DhAlg    DhAlgorithm `json:"dh_alg"`
	Pubkey   string      `json:"pubkey"`    // base64url Ed25519 public key (32 bytes)
	DhPubkey string      `json:"dh_pubkey"` // base64url ECDH public key (65 bytes P-256 / 32 bytes X25519)
	Endpoint string      `json:"endpoint"`  // https URL of the relay endpoint
	Nonce    string      `json:"nonce"`     // base64url 16 random bytes
	Ts       int64       `json:"ts"`        // unix seconds
}

PairingToken is exchanged out-of-band between two Frame operators to initiate pairing. JSON field names match casket-ts exactly for wire compatibility.

type PeerRecord

type PeerRecord struct {
	NexusID  string      `json:"nexus_id"`
	Pubkey   string      `json:"pubkey"`
	DhAlg    DhAlgorithm `json:"dh_alg"`
	DhPubkey string      `json:"dh_pubkey"`
	Endpoint string      `json:"endpoint"`
	PathID   string      `json:"path_id"`
	PairedAt int64       `json:"paired_at"`
}

PeerRecord is stored in ChannelStorage for each paired peer.

Jump to

Keyboard shortcuts

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