Help us shape the future of Go! Take the 2026 Go Developer Survey

noise

package
v1.3.101 Latest Latest
Warning

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

Go to latest
Published: Oct 13, 2026 License: AGPL-3.0 Imports: 23 Imported by: 0

Documentation

Overview

Package noise pkg/dmsg/noise/dh.go c1-net-dmsg

Package noise pkg/dmsg/noise/dh_pool_native.go c1-net-dmsg

Package noise pkg/dmsg/noise/net.go c1-net-dmsg

Package noise pkg/dmsg/noise/noise.go c1-net-dmsg

Package noise pkg/dmsg/noise/nonce_window.go c1-net-dmsg

Package noise pkg/dmsg/noise/pqhybrid.go c1-net-dmsg

Self-contained post-quantum hybrid key-agreement layer (ML-KEM-768) that composes with the classical Noise_KK handshake. See docs/design/pq-hybrid-noise-handshake.md.

This file is JUST the crypto: ephemeral ML-KEM keygen / encapsulate / decapsulate, and the HKDF combiner that mixes the classical Noise session key with the ML-KEM shared secret. It deliberately does NOT touch the live handshake — wiring the payloads + capability negotiation into the handshake is a separate, flag-gated change so this layer can be reviewed and tested in isolation. Everything here is Go stdlib (crypto/mlkem + crypto/hkdf), no new dependency.

Package noise pkg/dmsg/noise/read_writer.go c1-net-dmsg

Package noise pkg/dmsg/noise/rpcdialer.go c1-net-dmsg

RPCClientDialer is split out of net.go behind //go:build !tinygo because it imports net/rpc, which transitively pulls net/http — broken on the TinyGo js target. It is a server-side redial helper (a visor exposing an RPC server to a remote), never used by a dmsg client, so excluding it from TinyGo builds costs nothing. See docs/design/tinygo-dmsg-client.md.

Index

Constants

View Source
const MaxWriteSize = maxPayloadSize

MaxWriteSize is the largest amount for a single write.

View Source
const NonceWindowSize = 1024

NonceWindowSize is the number of recent nonces tracked for replay prevention. Must be a multiple of 64 for the bitmap implementation.

Variables

View Source
var (
	// ErrAlreadyServing is returned when an operation fails due to an operation
	// that is currently running.
	ErrAlreadyServing = errors.New("already serving")

	// HandshakeXK is the XK handshake pattern.
	// 		legend: s(static) e(ephemeral)
	//	<- s
	//	...
	//	-> e, es
	//	<- e, ee
	//	-> s, se
	HandshakeXK = noise.HandshakeXK

	// HandshakeKK is the KK handshake pattern.
	// 		legend: s(static) e(ephemeral)
	//	-> s
	//	<- s
	//	...
	//	-> e, es, ss
	//	<- e, ee, se
	HandshakeKK = noise.HandshakeKK

	// AcceptHandshakeTimeout determines how long a noise hs should take.
	AcceptHandshakeTimeout = time.Second * 10
)
View Source
var ErrInvalidCipherText = errors.New("noise decrypt unsafe: ciphertext cannot be less than 8 bytes")

ErrInvalidCipherText occurs when a ciphertext is received which is too short in size.

View Source
var ErrReadDetached = errors.New("noise: reads moved to a decoder")

ErrReadDetached is returned by Read once the stream has moved to a Decoder.

Functions

func InitiatorHandshake

func InitiatorHandshake(ns *Noise, r *bufio.Reader, w io.Writer) error

InitiatorHandshake performs a noise handshake as an initiator.

func ReadRawFrame

func ReadRawFrame(r *bufio.Reader) (p []byte, err error)

ReadRawFrame attempts to read a raw frame from a buffered reader.

func ResponderHandshake

func ResponderHandshake(ns *Noise, r *bufio.Reader, w io.Writer) error

ResponderHandshake performs a noise handshake as a responder.

func WriteRawFrame

func WriteRawFrame(w io.Writer, p []byte) ([]byte, error)

WriteRawFrame writes a raw frame (data prefixed with a uint16 len). It returns the bytes written.

Types

type Addr

type Addr struct {
	PK   cipher.PubKey
	Addr net.Addr
}

Addr is the address of a either an AppNode or ManagerNode.

func (Addr) Network

func (a Addr) Network() string

Network returns the network type.

func (Addr) String

func (a Addr) String() string

String implements fmt.Stringer

type CacheStats

type CacheStats struct {
	Hits      uint64
	Misses    uint64
	Evictions uint64
	Size      int
	Capacity  int
}

CacheStats is a snapshot of the noise DH cache counters. Hits/Misses are counted on every call to (Secp256k1).DH; Evictions is incremented each time a single entry is dropped to make room (one per eviction, not per overflowed insertion).

func GetCacheStats

func GetCacheStats() CacheStats

GetCacheStats returns a snapshot of the noise DH cache counters. Safe to call concurrently with DH.

type Config

type Config struct {
	LocalPK   cipher.PubKey // Local instance static public key.
	LocalSK   cipher.SecKey // Local instance static secret key.
	RemotePK  cipher.PubKey // Remote instance static public key.
	Initiator bool          // Whether the local instance initiates the connection.
}

Config hold noise parameters.

type Conn

type Conn struct {
	net.Conn
	// contains filtered or unexported fields
}

Conn wraps a net.Conn and encrypts the connection with noise.

func WrapConn

func WrapConn(conn net.Conn, ns *Noise, hsTimeout time.Duration) (*Conn, error)

WrapConn wraps a provided net.Conn with noise.

func (*Conn) ChannelBinding

func (c *Conn) ChannelBinding() []byte

ChannelBinding returns the completed handshake's channel binding — see Noise.ChannelBinding. Lets a caller key a sibling channel (e.g. the faithful-UDP datagram route, #2607) off this encrypted route's session.

func (*Conn) Decoder added in v1.3.100

func (c *Conn) Decoder() (*Decoder, []byte)

Decoder moves the rest of the stream to a Decoder, as ReadWriter.Decoder.

func (*Conn) LocalAddr

func (c *Conn) LocalAddr() net.Addr

LocalAddr returns the local address of the connection.

func (*Conn) Read

func (c *Conn) Read(b []byte) (int, error)

Read reads from the noise-encrypted connection.

func (*Conn) RemoteAddr

func (c *Conn) RemoteAddr() net.Addr

RemoteAddr returns the remote address of the connection.

func (*Conn) Write

func (c *Conn) Write(b []byte) (int, error)

Write writes to the noise-encrypted connection.

type Decoder added in v1.3.100

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

Decoder decrypts noise frames from a stream pushed to it in pieces of any size, for a reader driven by arriving data instead of a goroutine in Read.

func (*Decoder) Feed added in v1.3.100

func (d *Decoder) Feed(p []byte, emit func(plaintext []byte)) error

Feed decrypts every frame that p completes and passes the plaintext of each to emit, which must not keep it. An error is final.

type Listener

type Listener struct {
	net.Listener
	// contains filtered or unexported fields
}

Listener accepts incoming connections and encrypts with noise.

func WrapListener

func WrapListener(lis net.Listener, pk cipher.PubKey, sk cipher.SecKey, init bool, pattern noise.HandshakePattern) *Listener

WrapListener wraps a listener and encrypts incoming connections with noise.

func (*Listener) Accept

func (ml *Listener) Accept() (net.Conn, error)

Accept calls Accept from the underlying net.Listener and encrypts the obtained net.Conn with noise.

func (*Listener) Addr

func (ml *Listener) Addr() net.Addr

Addr returns the local address of the noise-encrypted Listener.

type Noise

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

Noise handles the handshake and the frame's cryptography. All operations on Noise are not guaranteed to be thread-safe.

func KKAndSecp256k1

func KKAndSecp256k1(config Config) (*Noise, error)

KKAndSecp256k1 creates a new Noise with:

  • KK pattern for handshake.
  • Secp256k1 for the curve.

func New

func New(pattern noise.HandshakePattern, config Config) (*Noise, error)

New creates a new Noise with:

  • provided pattern for handshake.
  • Secp256k1 for the curve.

func XKAndSecp256k1

func XKAndSecp256k1(config Config) (*Noise, error)

XKAndSecp256k1 creates a new Noise with:

  • XK pattern for handshake.
  • Secp256 for the curve.

func (*Noise) ChannelBinding

func (ns *Noise) ChannelBinding() []byte

ChannelBinding returns a value that uniquely identifies the completed handshake session — the Noise handshake hash. Both peers derive an identical value, and it is bound to the full transcript (static keys + ephemerals + any PQ hybrid payload), so it is safe to use as keying material for a sibling channel keyed off the same session. The faithful-UDP path (#2607) HKDFs this into a per-datagram AEAD master key so the datagram sibling of a route shares the reliable route's authenticated session without a second handshake.

Only meaningful once HandshakeFinished() is true; before that the binding is still over a partial transcript.

func (*Noise) DecryptUnsafe

func (ns *Noise) DecryptUnsafe(ciphertext []byte) ([]byte, error)

DecryptUnsafe decrypts ciphertext without interlocking, should only be used with external lock.

func (*Noise) DecryptWithNonceMap

func (ns *Noise) DecryptWithNonceMap(nm NonceMap, ciphertext []byte) ([]byte, error)

DecryptWithNonceMap is equivalent to DecryptNonce, instead it uses NonceMap to track nonces instead of a counter. Deprecated: Use DecryptWithNonceWindow instead.

func (*Noise) DecryptWithNonceWindow

func (ns *Noise) DecryptWithNonceWindow(nw *NonceWindow, ciphertext []byte) ([]byte, error)

DecryptWithNonceWindow decrypts ciphertext using a sliding window for nonce tracking. Unlike DecryptWithNonceMap, memory usage is bounded to O(NonceWindowSize) regardless of how many messages are decrypted over the session's lifetime.

func (*Noise) EncryptUnsafe

func (ns *Noise) EncryptUnsafe(plaintext []byte) []byte

EncryptUnsafe encrypts plaintext without interlocking, should only be used with external lock.

func (*Noise) GetDecNonce

func (ns *Noise) GetDecNonce() uint64

GetDecNonce returns underlying decNonce.

func (*Noise) GetEncNonce

func (ns *Noise) GetEncNonce() uint64

GetEncNonce returns underlying encNonce.

func (*Noise) HandshakeFinished

func (ns *Noise) HandshakeFinished() bool

HandshakeFinished indicate whether handshake was completed.

func (*Noise) LocalStatic

func (ns *Noise) LocalStatic() cipher.PubKey

LocalStatic returns the local static public key.

func (*Noise) MakeHandshakeMessage

func (ns *Noise) MakeHandshakeMessage() (res []byte, err error)

MakeHandshakeMessage generates handshake message for a current handshake state. The handshake payload carries the post-quantum offer/response (ML-KEM public key from the initiator, ciphertext from the responder); see pqOfferPayload.

func (*Noise) OpenWithNonce

func (ns *Noise) OpenWithNonce(nonce uint64, ciphertext []byte) ([]byte, error)

OpenWithNonce decrypts a frame sealed by SealWithNonce, using the EXPLICIT nonce (the frame's stream sequence). It does NOT touch decNonce and imposes no ordering requirement, so out-of-order arrival across mux legs is fine. Replay is handled one layer up by the reorder buffer (a sequence at or below the delivered frontier is dropped). Returns an error if the handshake has not produced a transport cipher yet or the tag fails to verify.

func (*Noise) PQActive

func (ns *Noise) PQActive() bool

PQActive reports whether the session negotiated the post-quantum hybrid (both peers exchanged ML-KEM material and the shared secret was mixed into the transport keys). False means a classical-only handshake (e.g. an older peer).

func (*Noise) ProcessHandshakeMessage

func (ns *Noise) ProcessHandshakeMessage(msg []byte) (err error)

ProcessHandshakeMessage processes a received handshake message and appends the payload.

func (*Noise) RemoteStatic

func (ns *Noise) RemoteStatic() cipher.PubKey

RemoteStatic returns the remote static public key. Returns an empty public key if the peer static key is invalid.

func (*Noise) SealWithNonce

func (ns *Noise) SealWithNonce(nonce uint64, plaintext []byte) []byte

SealWithNonce encrypts plaintext under the transport-phase cipher using an EXPLICIT nonce supplied by the caller, and does NOT touch the internal encNonce counter. This is the per-frame AEAD primitive for the mux inverse- multiplexer: each mux DATA frame is sealed with its own stream sequence number as the nonce, so frames can be decrypted INDEPENDENTLY and OUT OF ORDER (no stateful cipher to desync). The caller MUST guarantee nonce uniqueness per key — the mux sequence is assigned exactly once per frame, so it is unique by construction. The 8-byte nonce is NOT prepended (unlike EncryptUnsafe): it is carried in the mux packet's own sequence field. Returns nil if the handshake has not produced a transport cipher yet.

func (*Noise) WriterTurn

func (ns *Noise) WriterTurn() bool

WriterTurn reports whether the NEXT handshake message is ours to WRITE (via MakeHandshakeMessage) rather than to read. The initiator writes the even-indexed handshake messages and reads the odd ones; the responder is the mirror. Callers use this to avoid MakeHandshakeMessage out of turn, which the underlying state machine rejects ("unexpected call to WriteMessage should be ReadMessage"). Returns false once the handshake is finished.

type NonceMap

type NonceMap map[uint64]struct{}

NonceMap is a map of used nonces. Deprecated: Use NonceWindow instead for bounded memory usage.

type NonceWindow

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

NonceWindow tracks nonces using a sliding window to prevent replay attacks without unbounded memory growth. It stores the highest nonce seen and a bitmap of the last NonceWindowSize nonces. Nonces older than the window are assumed to be replays.

This replaces the unbounded NonceMap which grew forever on long-lived sessions (e.g., setup-node handling thousands of streams).

func NewNonceWindow

func NewNonceWindow() *NonceWindow

NewNonceWindow creates a new NonceWindow.

func (*NonceWindow) Check

func (nw *NonceWindow) Check(nonce uint64) error

Check returns nil if the nonce is valid (not a replay, not too old). If valid, the nonce is recorded in the window.

type RPCClientDialer

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

RPCClientDialer attempts to redial to a remotely served RPCClient. It exposes an RPCServer to the remote server. The connection is encrypted via noise.

func NewRPCClientDialer

func NewRPCClientDialer(addr string, pattern noise.HandshakePattern, config Config) *RPCClientDialer

NewRPCClientDialer creates a new RPCClientDialer.

func (*RPCClientDialer) Close

func (d *RPCClientDialer) Close() (err error)

Close closes the handler.

func (*RPCClientDialer) Run

func (d *RPCClientDialer) Run(srv *rpc.Server, retry time.Duration) error

Run repeatedly dials to remote until a successful connection is established. It exposes a RPC Server. It will return if Close is called or crypto fails.

type ReadWriter

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

ReadWriter implements noise encrypted read writer.

func NewReadWriter

func NewReadWriter(rw io.ReadWriter, ns *Noise) *ReadWriter

NewReadWriter constructs a new ReadWriter.

func (*ReadWriter) Buffered

func (rw *ReadWriter) Buffered() int

Buffered returns the number of bytes that can be read from the buffer rawInput.

func (*ReadWriter) ChannelBinding

func (rw *ReadWriter) ChannelBinding() []byte

ChannelBinding returns the completed handshake's channel binding — see Noise.ChannelBinding. Meaningful only after Handshake has returned.

func (*ReadWriter) Decoder added in v1.3.100

func (rw *ReadWriter) Decoder() (*Decoder, []byte)

Decoder moves the rest of the stream to a Decoder and returns it with the plaintext rw had decrypted but not yet returned. rw must not be read after.

func (*ReadWriter) Handshake

func (rw *ReadWriter) Handshake(hsTimeout time.Duration) error

Handshake performs a Noise handshake using the provided io.ReadWriter.

func (*ReadWriter) LocalStatic

func (rw *ReadWriter) LocalStatic() cipher.PubKey

LocalStatic returns the local static public key.

func (*ReadWriter) Read

func (rw *ReadWriter) Read(p []byte) (int, error)

func (*ReadWriter) RemoteStatic

func (rw *ReadWriter) RemoteStatic() cipher.PubKey

RemoteStatic returns the remote static public key.

func (*ReadWriter) Unread

func (rw *ReadWriter) Unread() []byte

Unread returns a copy of the bytes the handshake reader has buffered past the final handshake message. In an XK handshake the initiator may start writing session frames the moment it has sent its last message, so those frames can land in the responder's read buffer together with that message. They are valid post-handshake data and must be handed to the session transport, not discarded.

func (*ReadWriter) Write

func (rw *ReadWriter) Write(p []byte) (n int, err error)

type Secp256k1

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

Secp256k1 implements `noise.DHFunc`. The zero value computes every DH. Built with the handshake's own static secret key and the peer's static public key (see New), it caches the one DH that repeats between the same two peers: static-static.

func (Secp256k1) DH

func (d Secp256k1) DH(sk, pk []byte) ([]byte, error)

DH helps to implement `noise.DHFunc`.

func (Secp256k1) DHLen

func (Secp256k1) DHLen() int

DHLen helps to implement `noise.DHFunc`.

func (Secp256k1) DHName

func (Secp256k1) DHName() string

DHName helps to implement `noise.DHFunc`.

func (Secp256k1) GenerateKeypair

func (Secp256k1) GenerateKeypair(_ io.Reader) (noise.DHKey, error)

GenerateKeypair helps to implement `noise.DHFunc`.

Jump to

Keyboard shortcuts

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